diff --git a/panda/src/device/Sources.pp b/panda/src/device/Sources.pp index e3caf8c72d..b3760c212b 100644 --- a/panda/src/device/Sources.pp +++ b/panda/src/device/Sources.pp @@ -7,16 +7,30 @@ dgraph display gobj sgraph graph gsgbase ipc mathutil linmath putil #define SOURCES \ - adinputNode.cxx adinputNode.h analogData.I analogData.cxx \ - analogData.h buttonData.I buttonData.cxx buttonData.h \ - clientBase.cxx clientBase.h config_device.cxx config_device.h \ + analogData.I analogData.cxx analogData.h \ + analogNode.I analogNode.cxx analogNode.h \ + buttonNode.I buttonNode.h buttonNode.cxx \ + clientAnalogDevice.I clientAnalogDevice.cxx clientAnalogDevice.h \ + clientBase.I clientBase.cxx clientBase.h \ + clientButtonDevice.I clientButtonDevice.cxx clientButtonDevice.h \ + clientDevice.I clientDevice.cxx clientDevice.h \ + clientTrackerDevice.I clientTrackerDevice.cxx clientTrackerDevice.h \ + config_device.cxx config_device.h \ dialData.I dialData.cxx dialData.h mouse.cxx mouse.h trackerData.I \ - trackerData.cxx trackerData.h trackerNode.cxx trackerNode.h + trackerData.cxx trackerData.h \ + trackerNode.I trackerNode.cxx trackerNode.h #define INSTALL_HEADERS \ - adinputNode.h analogData.I analogData.h buttonData.I buttonData.h \ - clientBase.h config_device.h dialData.I dialData.h mouse.h \ - trackerData.I trackerData.h trackerNode.h + analogData.I analogData.h \ + analogNode.I analogNode.h \ + buttonNode.I buttonNode.h \ + clientAnalogDevice.I clientAnalogDevice.h \ + clientBase.I clientBase.h \ + clientButtonDevice.I clientButtonDevice.h \ + clientDevice.I clientDevice.h \ + clientTrackerDevice.I clientTrackerDevice.h \ + config_device.h dialData.I dialData.h mouse.h \ + trackerData.I trackerData.h trackerNode.I trackerNode.h #define IGATESCAN all diff --git a/panda/src/device/adinputNode.cxx b/panda/src/device/adinputNode.cxx deleted file mode 100644 index cb49bfb014..0000000000 --- a/panda/src/device/adinputNode.cxx +++ /dev/null @@ -1,124 +0,0 @@ -// Filename: adinputNode.cxx -// Created by: jason (08Aug00) -// -//////////////////////////////////////////////////////////////////// - -#include "adinputNode.h" -#include "config_device.h" - -//////////////////////////////////////////////////////////////////// -// Static variables -//////////////////////////////////////////////////////////////////// -TypeHandle ADInputNode::_type_handle; - -TypeHandle ADInputNode::_dtime_type; -TypeHandle ADInputNode::_dial_id_type; -TypeHandle ADInputNode::_change_type; - -TypeHandle ADInputNode::_btime_type; -TypeHandle ADInputNode::_button_id_type; -TypeHandle ADInputNode::_state_type; - -TypeHandle ADInputNode::_atime_type; -TypeHandle ADInputNode::_channels_type; - - -//////////////////////////////////////////////////////////////////// -// Function: ADInputNode::Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -ADInputNode:: -ADInputNode(PT(ClientBase) client, const string &adinput) : - DataNode(adinput), _client(client), _adinput(adinput) -{ - _client->add_remote_analog(_adinput); - _client->add_remote_button(_adinput); - _client->add_remote_dial(_adinput); - - _dtime = new DoubleDataAttribute(); - _dial_id = new IntDataAttribute(); - _change = new DoubleDataAttribute(); - - _btime = new DoubleDataAttribute(); - _button_id = new IntDataAttribute(); - _state = new IntDataAttribute(); - - _atime = new DoubleDataAttribute(); - _channels = new DoublePtrDataAttribute(); - - _adinput_attrib.set_attribute(_dtime_type, _dtime); - _adinput_attrib.set_attribute(_dial_id_type, _dial_id); - _adinput_attrib.set_attribute(_change_type, _change); - - _adinput_attrib.set_attribute(_btime_type, _btime); - _adinput_attrib.set_attribute(_button_id_type, _button_id); - _adinput_attrib.set_attribute(_state_type, _state); - - _adinput_attrib.set_attribute(_atime_type, _atime); - _adinput_attrib.set_attribute(_channels_type, _channels); -} - -//////////////////////////////////////////////////////////////////// -// Function: ADInputNode::transmit_data -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void ADInputNode:: -transmit_data(NodeAttributes &data) { - AnalogData new_analog = _client->get_analog_data(_adinput); - ButtonData new_button = _client->get_button_data(_adinput); - DialData new_dial = _client->get_dial_data(_adinput); - - _dtime->set_value(new_dial.dtime); - _dial_id->set_value(new_dial.dial_id); - _change->set_value(new_dial.change); - - _btime->set_value(new_button.btime); - _button_id->set_value(new_button.button_id); - _state->set_value(new_button.state); - - _atime->set_value(new_analog.atime); - _channels->set_value((double*)new_analog.channels); - - data = _adinput_attrib; -} - -//////////////////////////////////////////////////////////////////// -// Function: ADInputNode::init_type -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -void ADInputNode:: -init_type() { - DataNode::init_type(); - register_type(_type_handle, "ADInputNode", - DataNode::get_class_type()); - - DoubleDataTransition::init_type(); - IntDataTransition::init_type(); - DoublePtrDataTransition::init_type(); - - register_data_transition(_dtime_type, "Dial Time", - DoubleDataTransition::get_class_type()); - register_data_transition(_dial_id_type, "Dial ID", - IntDataTransition::get_class_type()); - register_data_transition(_change_type, "Dial Change", - DoubleDataTransition::get_class_type()); - - register_data_transition(_btime_type, "Button Time", - DoubleDataTransition::get_class_type()); - register_data_transition(_button_id_type, "Button ID", - IntDataTransition::get_class_type()); - register_data_transition(_state_type, "Button State", - IntDataTransition::get_class_type()); - - register_data_transition(_atime_type, "Analog Time", - DoubleDataTransition::get_class_type()); - register_data_transition(_channels_type, "Analog Channels", - DoublePtrDataTransition::get_class_type()); -} - - - - diff --git a/panda/src/device/adinputNode.h b/panda/src/device/adinputNode.h deleted file mode 100644 index e02758b8d5..0000000000 --- a/panda/src/device/adinputNode.h +++ /dev/null @@ -1,78 +0,0 @@ -// Filename: cerealboxNode.h -// Created by: jason (08Aug00) -// -//////////////////////////////////////////////////////////////////// - -#ifndef _ADINPUT_NODE -#define _ADINPUT_NODE - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "clientBase.h" - -//////////////////////////////////////////////////////////////////// -// Class : ADInputNode -// Description : Reads the analog, buttons and dials from a adinput -// and sends it down the DataGraph -//////////////////////////////////////////////////////////////////// -class EXPCL_PANDA ADInputNode : public DataNode { -PUBLISHED: - ADInputNode(PT(ClientBase) client, const string &adinput); - -public: - virtual void transmit_data(NodeAttributes &data); - -public: - NodeAttributes _adinput_attrib; - - PT(DoubleDataAttribute) _btime; - PT(IntDataAttribute) _button_id; - PT(IntDataAttribute) _state; - - PT(DoubleDataAttribute) _dtime; - PT(IntDataAttribute) _dial_id; - PT(DoubleDataAttribute) _change; - - PT(DoubleDataAttribute) _atime; - PT(DoublePtrDataAttribute) _channels; - - static TypeHandle _btime_type; - static TypeHandle _button_id_type; - static TypeHandle _state_type; - - static TypeHandle _dtime_type; - static TypeHandle _dial_id_type; - static TypeHandle _change_type; - - static TypeHandle _atime_type; - static TypeHandle _channels_type; - -protected: - PT(ClientBase) _client; - string _adinput; - -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; -}; - -#endif diff --git a/panda/src/device/analogData.I b/panda/src/device/analogData.I deleted file mode 100644 index b9eec10896..0000000000 --- a/panda/src/device/analogData.I +++ /dev/null @@ -1,62 +0,0 @@ -// Filename: analogData.I -// Created by: jason (04Aug00) -// -//////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////// -// Function: AnalogData::Default Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE AnalogData:: -AnalogData() : - atime(0) -{ - channels = new vector_double; - stored_channels = new vector_double; -} - -//////////////////////////////////////////////////////////////////// -// Function: AnalogData::Default Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE AnalogData:: -~AnalogData() { - delete channels; - delete stored_channels; -} - -//////////////////////////////////////////////////////////////////// -// Function: AnalogData::Copy Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE AnalogData:: -AnalogData(const AnalogData ©) { - (*this) = copy; -} - -//////////////////////////////////////////////////////////////////// -// Function: AnalogData::Copy Assignment Operator -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE AnalogData &AnalogData:: -operator = (const AnalogData ©) { - atime = copy.atime; - channels = new vector_double(*copy.channels); - stored_channels = new vector_double(*copy.stored_channels); - - return *this; -} - -//////////////////////////////////////////////////////////////////// -// Function: AnalogData::none -// Access: Public, Static -// Description: Returns an empty AnalogData object -//////////////////////////////////////////////////////////////////// -INLINE const AnalogData &AnalogData:: -none() { - return _none; -} diff --git a/panda/src/device/analogData.cxx b/panda/src/device/analogData.cxx deleted file mode 100644 index 5557801cfc..0000000000 --- a/panda/src/device/analogData.cxx +++ /dev/null @@ -1,9 +0,0 @@ -// Filename: analogData.cxx -// Created by: jason (04Aug00) -// -//////////////////////////////////////////////////////////////////// - -#include "analogData.h" - -// This is initialized to zero by static initialization. -AnalogData AnalogData::_none; diff --git a/panda/src/device/analogData.h b/panda/src/device/analogData.h deleted file mode 100644 index 7fdd2532eb..0000000000 --- a/panda/src/device/analogData.h +++ /dev/null @@ -1,37 +0,0 @@ -// Filename: analogData.h -// Created by: jason (04Aug00) -// -//////////////////////////////////////////////////////////////////// - -#ifndef ANALOG_DATA -#define ANALOG_DATA - -#include -#include - -class EXPCL_PANDA AnalogData { -public: - INLINE AnalogData(); - INLINE ~AnalogData(); - INLINE AnalogData(const AnalogData ©); - INLINE AnalogData &operator = (const AnalogData ©); - - INLINE static const AnalogData &none(); - - double atime; - //These two pointers are so that we can return a reference to the - //current channel values, but not incure the overhead of copying all - //those values everywhere. We need two so that we can implement a - //rotating pointer scheme to ensure that there are no collisions - //between writing and reading. - vector_double *channels; -private: - vector_double *stored_channels; - static AnalogData _none; - - friend class ClientBase; -}; - -#include "analogData.I" - -#endif diff --git a/panda/src/device/analogNode.I b/panda/src/device/analogNode.I new file mode 100644 index 0000000000..aabd277839 --- /dev/null +++ b/panda/src/device/analogNode.I @@ -0,0 +1,119 @@ +// Filename: analogNode.I +// Created by: drose (26Jan01) +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: AnalogNode::OutputData::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE AnalogNode::OutputData:: +OutputData() { + _index = -1; + _flip = false; +} + +//////////////////////////////////////////////////////////////////// +// Function: AnalogNode::is_valid +// Access: Public +// Description: Returns true if the AnalogNode is valid and +// connected to a server, false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool AnalogNode:: +is_valid() const { + return (_analog != (ClientAnalogDevice *)NULL) && _analog->is_connected(); +} + +//////////////////////////////////////////////////////////////////// +// Function: AnalogNode::get_num_controls +// Access: Public +// Description: Returns the number of analog controls known to the +// AnalogNode. This number may change as more controls +// are discovered. +//////////////////////////////////////////////////////////////////// +INLINE int AnalogNode:: +get_num_controls() const { + return _analog->get_num_controls(); +} + +//////////////////////////////////////////////////////////////////// +// Function: AnalogNode::get_control_state +// Access: Public +// Description: Returns the current position of indicated analog +// control identified by its index number, or 0.0 if +// the control is unknown. The normal range of a single +// control is -1.0 to 1.0. +//////////////////////////////////////////////////////////////////// +INLINE double AnalogNode:: +get_control_state(int index) const { + return _analog->get_control_state(index); +} + +//////////////////////////////////////////////////////////////////// +// Function: AnalogNode::is_control_known +// Access: Public +// Description: Returns true if the state of the indicated analog +// control is known, or false if we have never heard +// anything about this particular control. +//////////////////////////////////////////////////////////////////// +INLINE bool AnalogNode:: +is_control_known(int index) const { + return _analog->is_control_known(index); +} + +//////////////////////////////////////////////////////////////////// +// Function: AnalogNode::set_output +// Access: Public +// Description: Causes a particular analog control to be placed in +// the data graph for the indicated channel. Normally, +// a mouse uses channels 0 and 1 for the X and Y +// information, respectively; channels 0, 1, and 2 are +// available. If flip is true, the analog control value +// will be reversed before outputting it. +//////////////////////////////////////////////////////////////////// +INLINE void AnalogNode:: +set_output(int channel, int index, bool flip) { + nassertv(channel >= 0 && channel < max_outputs); + _outputs[channel]._index = index; + _outputs[channel]._flip = flip; +} + +//////////////////////////////////////////////////////////////////// +// Function: AnalogNode::clear_output +// Access: Public +// Description: Removes the output to the data graph associated with +// the indicated channel. See set_output(). +//////////////////////////////////////////////////////////////////// +INLINE void AnalogNode:: +clear_output(int channel) { + nassertv(channel >= 0 && channel < max_outputs); + _outputs[channel]._index = -1; +} + +//////////////////////////////////////////////////////////////////// +// Function: AnalogNode::get_output +// Access: Public +// Description: Returns the analog control index that is output to +// the data graph on the indicated channel, or -1 if no +// control is output on that channel. See set_output(). +//////////////////////////////////////////////////////////////////// +INLINE int AnalogNode:: +get_output(int channel) const { + nassertr(channel >= 0 && channel < max_outputs, -1); + return _outputs[channel]._index; +} + +//////////////////////////////////////////////////////////////////// +// Function: AnalogNode::is_output_flipped +// Access: Public +// Description: Returns true if the analog control index that is +// output to the data graph on the indicated channel is +// flipped. See set_output(). +//////////////////////////////////////////////////////////////////// +INLINE bool AnalogNode:: +is_output_flipped(int channel) const { + nassertr(channel >= 0 && channel < max_outputs, false); + return _outputs[channel]._flip; +} diff --git a/panda/src/device/analogNode.cxx b/panda/src/device/analogNode.cxx new file mode 100644 index 0000000000..150eee19dc --- /dev/null +++ b/panda/src/device/analogNode.cxx @@ -0,0 +1,116 @@ +// Filename: analogNode.cxx +// Created by: drose (26Jan01) +// +//////////////////////////////////////////////////////////////////// + +#include "analogNode.h" +#include "config_device.h" + +//////////////////////////////////////////////////////////////////// +// Static variables +//////////////////////////////////////////////////////////////////// +TypeHandle AnalogNode::_type_handle; + +TypeHandle AnalogNode::_xyz_type; + +//////////////////////////////////////////////////////////////////// +// Function: AnalogNode::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +AnalogNode:: +AnalogNode(ClientBase *client, const string &device_name) : + DataNode(device_name) +{ + nassertv(client != (ClientBase *)NULL); + PT(ClientDevice) device = + client->get_device(ClientAnalogDevice::get_class_type(), device_name); + + if (device == (ClientDevice *)NULL) { + device_cat.warning() + << "Unable to open analog device " << device_name << "\n"; + return; + } + + if (!device->is_of_type(ClientAnalogDevice::get_class_type())) { + device_cat.error() + << "Inappropriate device type " << device->get_type() + << " created; expected a ClientAnalogDevice.\n"; + return; + } + + _analog = DCAST(ClientAnalogDevice, device); + + _xyz = new Vec3DataAttribute(LPoint3f(0, 0, 0)); + _attrib.set_attribute(_xyz_type, _xyz); +} + +//////////////////////////////////////////////////////////////////// +// Function: AnalogNode::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +AnalogNode:: +~AnalogNode() { + // When the _analog pointer destructs, the ClientAnalogDevice + // disconnects itself from the ClientBase, and everything that needs + // to get turned off does. Magic. +} + +//////////////////////////////////////////////////////////////////// +// Function: AnalogNode::write +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void AnalogNode:: +write(ostream &out, int indent_level) const { + DataNode::write(out, indent_level); + + if (_analog != (ClientAnalogDevice *)NULL) { + _analog->write_controls(out, indent_level + 2); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: AnalogNode::transmit_data +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void AnalogNode:: +transmit_data(NodeAttributes &data) { + if (is_valid()) { + _analog->poll(); + + LPoint3f out(0.0, 0.0, 0.0); + + for (int i = 0; i < max_outputs; i++) { + if (_outputs[i]._index >= 0 && is_control_known(_outputs[i]._index)) { + if (_outputs[i]._flip) { + out[i] = -get_control_state(_outputs[i]._index); + } else { + out[i] = get_control_state(_outputs[i]._index); + } + } + } + _xyz->set_value(out); + } + + data = _attrib; +} + +//////////////////////////////////////////////////////////////////// +// Function: AnalogNode::init_type +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void AnalogNode:: +init_type() { + DataNode::init_type(); + register_type(_type_handle, "AnalogNode", + DataNode::get_class_type()); + + Vec3DataTransition::init_type(); + register_data_transition(_xyz_type, "XYZ", + Vec3DataTransition::get_class_type()); +} + diff --git a/panda/src/device/analogNode.h b/panda/src/device/analogNode.h new file mode 100644 index 0000000000..05708a5c6f --- /dev/null +++ b/panda/src/device/analogNode.h @@ -0,0 +1,101 @@ +// Filename: analogNode.h +// Created by: drose (26Jan01) +// +//////////////////////////////////////////////////////////////////// + +#ifndef ANALOGNODE_H +#define ANALOGNODE_H + +#include + +#include "clientBase.h" +#include "clientAnalogDevice.h" + +#include +#include +#include +#include + + +//////////////////////////////////////////////////////////////////// +// Class : AnalogNode +// Description : This is the primary interface to analog controls like +// sliders and joysticks associated with a ClientBase. +// This creates a node that connects to the named analog +// device, if it exists, and provides hooks to the user +// to read the state of any of the sequentially numbered +// controls associated with that device. +// +// Each control can return a value ranging from -1 to 1, +// reflecting the current position of the control within +// its total range of motion. +// +// The user may choose up to three analog controls to +// place on the data graph as the three channels of an +// XYZ datagram, similarly to the way a mouse places its +// position data. In this way, an AnalogNode may be +// used in place of a mouse. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA AnalogNode : public DataNode { +PUBLISHED: + AnalogNode(ClientBase *client, const string &device_name); + virtual ~AnalogNode(); + + INLINE bool is_valid() const; + + INLINE int get_num_controls() const; + + INLINE double get_control_state(int index) const; + INLINE bool is_control_known(int index) const; + + INLINE void set_output(int channel, int index, bool flip); + INLINE void clear_output(int channel); + INLINE int get_output(int channel) const; + INLINE bool is_output_flipped(int channel) const; + +public: + virtual void write(ostream &out, int indent_level = 0) const; + +private: + class OutputData { + public: + INLINE OutputData(); + int _index; + bool _flip; + }; + + enum { max_outputs = 3 }; + OutputData _outputs[max_outputs]; + +//////////////////////////////////////////////////////////////////// +// From parent class DataNode +//////////////////////////////////////////////////////////////////// +public: + virtual void + transmit_data(NodeAttributes &data); + + NodeAttributes _attrib; + PT(Vec3DataAttribute) _xyz; + + static TypeHandle _xyz_type; + +private: + PT(ClientAnalogDevice) _analog; + +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 "analogNode.I" + +#endif diff --git a/panda/src/device/buttonData.I b/panda/src/device/buttonData.I deleted file mode 100644 index a4d45ac6a0..0000000000 --- a/panda/src/device/buttonData.I +++ /dev/null @@ -1,49 +0,0 @@ -// Filename: buttonData.I -// Created by: jason (07Aug00) -// -//////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////// -// Function: ButtonData::Default Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE ButtonData:: -ButtonData() : - btime(0), button_id(0), state(0) -{ -} - -//////////////////////////////////////////////////////////////////// -// Function: ButtonData::Copy Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE ButtonData:: -ButtonData(const ButtonData ©) { - (*this) = copy; -} - -//////////////////////////////////////////////////////////////////// -// Function: ButtonData::Copy Assignment Operator -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE ButtonData &ButtonData:: -operator = (const ButtonData ©) { - btime = copy.btime; - button_id = copy.button_id; - state = copy.state; - - return *this; -} - -//////////////////////////////////////////////////////////////////// -// Function: ButtonData::none -// Access: Public, Static -// Description: Returns an empty ButtonData object -//////////////////////////////////////////////////////////////////// -INLINE const ButtonData &ButtonData:: -none() { - return _none; -} diff --git a/panda/src/device/buttonData.cxx b/panda/src/device/buttonData.cxx deleted file mode 100644 index d82899a1b0..0000000000 --- a/panda/src/device/buttonData.cxx +++ /dev/null @@ -1,9 +0,0 @@ -// Filename: buttonData.cxx -// Created by: jason (04Aug00) -// -//////////////////////////////////////////////////////////////////// - -#include "buttonData.h" - -// This is initialized to zero by static initialization. -ButtonData ButtonData::_none; diff --git a/panda/src/device/buttonData.h b/panda/src/device/buttonData.h deleted file mode 100644 index e54bc76e5d..0000000000 --- a/panda/src/device/buttonData.h +++ /dev/null @@ -1,29 +0,0 @@ -// Filename: buttonData.h -// Created by: jason (07Aug00) -// -//////////////////////////////////////////////////////////////////// - -#ifndef BUTTON_DATA -#define BUTTON_DATA - -#include -#include - -class EXPCL_PANDA ButtonData { -public: - INLINE ButtonData(); - INLINE ButtonData(const ButtonData ©); - INLINE ButtonData &operator = (const ButtonData ©); - - INLINE static const ButtonData &none(); - - double btime; - int button_id; - int state; -private: - static ButtonData _none; -}; - -#include "buttonData.I" - -#endif diff --git a/panda/src/device/buttonNode.I b/panda/src/device/buttonNode.I new file mode 100644 index 0000000000..35c4af1060 --- /dev/null +++ b/panda/src/device/buttonNode.I @@ -0,0 +1,87 @@ +// Filename: buttonNode.I +// Created by: drose (31Dec69) +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: ButtonNode::is_valid +// Access: Public +// Description: Returns true if the ButtonNode is valid and +// connected to a server, false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool ButtonNode:: +is_valid() const { + return (_button != (ClientButtonDevice *)NULL) && _button->is_connected(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonNode::get_num_buttons +// Access: Public +// Description: Returns the number of buttons known to the +// ButtonNode. This includes those buttons whose state +// has been seen, as well as buttons that have been +// associated with a ButtonHandle even if their state is +// unknown. This number may change as more buttons are +// discovered. +//////////////////////////////////////////////////////////////////// +INLINE int ButtonNode:: +get_num_buttons() const { + return _button->get_num_buttons(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonNode::set_button_map +// Access: Public +// Description: Associates the indicated ButtonHandle with the button +// of the indicated index number. When the given button +// index changes state, a corresponding ButtonEvent will +// be generated with the given ButtonHandle. Pass +// ButtonHandle::none() to turn off any association. +// +// It is not necessary to call this if you simply want +// to query the state of the various buttons by index +// number; this is only necessary in order to generate +// ButtonEvents when the buttons change state. +//////////////////////////////////////////////////////////////////// +INLINE void ButtonNode:: +set_button_map(int index, ButtonHandle button) { + _button->set_button_map(index, button); +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonNode::get_button_map +// Access: Public +// Description: Returns the ButtonHandle that was previously +// associated with the given index number by +// a call to set_button_map(), or ButtonHandle::none() +// if no button was associated. +//////////////////////////////////////////////////////////////////// +INLINE ButtonHandle ButtonNode:: +get_button_map(int index) const { + return _button->get_button_map(index); +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonNode::get_button_state +// Access: Public +// Description: Returns true if the indicated button (identified by +// its index number) is currently known to be down, or +// false if it is up or unknown. +//////////////////////////////////////////////////////////////////// +INLINE bool ButtonNode:: +get_button_state(int index) const { + return _button->get_button_state(index); +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonNode::is_button_known +// Access: Public +// Description: Returns true if the state of the indicated button is +// known, or false if we have never heard anything about +// this particular button. +//////////////////////////////////////////////////////////////////// +INLINE bool ButtonNode:: +is_button_known(int index) const { + return _button->is_button_known(index); +} diff --git a/panda/src/device/buttonNode.cxx b/panda/src/device/buttonNode.cxx new file mode 100644 index 0000000000..9a17233d45 --- /dev/null +++ b/panda/src/device/buttonNode.cxx @@ -0,0 +1,132 @@ +// Filename: buttonNode.cxx +// Created by: drose (31Dec69) +// +//////////////////////////////////////////////////////////////////// + +#include "buttonNode.h" +#include "config_device.h" + +#include + +//////////////////////////////////////////////////////////////////// +// Static variables +//////////////////////////////////////////////////////////////////// +TypeHandle ButtonNode::_type_handle; + +TypeHandle ButtonNode::_button_events_type; + +//////////////////////////////////////////////////////////////////// +// Function: ButtonNode::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +ButtonNode:: +ButtonNode(ClientBase *client, const string &device_name) : + DataNode(device_name) +{ + nassertv(client != (ClientBase *)NULL); + PT(ClientDevice) device = + client->get_device(ClientButtonDevice::get_class_type(), device_name); + + if (device == (ClientDevice *)NULL) { + device_cat.warning() + << "Unable to open button device " << device_name << "\n"; + return; + } + + if (!device->is_of_type(ClientButtonDevice::get_class_type())) { + device_cat.error() + << "Inappropriate device type " << device->get_type() + << " created; expected a ClientButtonDevice.\n"; + return; + } + + _button = DCAST(ClientButtonDevice, device); + + if (_button != (ClientButtonDevice *)NULL) { + _button_events = new ButtonEventDataAttribute(); + _attrib.set_attribute(_button_events_type, _button_events); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonNode::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +ButtonNode:: +~ButtonNode() { + // When the _button pointer destructs, the ClientButtonDevice + // disconnects itself from the ClientBase, and everything that needs + // to get turned off does. Magic. +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonNode::output +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void ButtonNode:: +output(ostream &out) const { + DataNode::output(out); + + if (_button != (ClientButtonDevice *)NULL) { + out << " ("; + _button->output_buttons(out); + out << ")"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonNode::write +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void ButtonNode:: +write(ostream &out, int indent_level) const { + DataNode::write(out, indent_level); + + if (_button != (ClientButtonDevice *)NULL) { + _button->write_buttons(out, indent_level + 2); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonNode::transmit_data +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void ButtonNode:: +transmit_data(NodeAttributes &data) { + if (is_valid()) { + _button->poll(); + _button->lock(); + (*_button_events) = (*_button->get_button_events()); + _button->get_button_events()->clear(); + _button->unlock(); + + if (device_cat.is_debug()) { + device_cat.debug() << "ButtonNode:attributes" << endl; + _attrib.write(device_cat.debug(false), 3); + } + } + + data = _attrib; +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonNode::init_type +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void ButtonNode:: +init_type() { + DataNode::init_type(); + register_type(_type_handle, "ButtonNode", + DataNode::get_class_type()); + + ButtonEventDataTransition::init_type(); + register_data_transition(_button_events_type, "ButtonEvents", + ButtonEventDataTransition::get_class_type()); +} + diff --git a/panda/src/device/buttonNode.h b/panda/src/device/buttonNode.h new file mode 100644 index 0000000000..5fed20af04 --- /dev/null +++ b/panda/src/device/buttonNode.h @@ -0,0 +1,84 @@ +// Filename: buttonNode.h +// Created by: drose (31Dec69) +// +//////////////////////////////////////////////////////////////////// + +#ifndef BUTTONNODE_H +#define BUTTONNODE_H + +#include + +#include "clientBase.h" +#include "clientButtonDevice.h" + +#include +#include + + +//////////////////////////////////////////////////////////////////// +// Class : ButtonNode +// Description : This is the primary interface to on/off button +// devices associated with a ClientBase. This creates a +// node that connects to the named button device, if it +// exists, and provides hooks to the user to read the +// state of any of the sequentially numbered buttons +// associated with that device. +// +// It also can associate an arbitrary ButtonHandle with +// each button; when buttons are associated with +// ButtonHandles, this node will put appropriate up and +// down events on the data graph for each button state +// change. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA ButtonNode : public DataNode { +PUBLISHED: + ButtonNode(ClientBase *client, const string &device_name); + virtual ~ButtonNode(); + + INLINE bool is_valid() const; + + INLINE int get_num_buttons() const; + + INLINE void set_button_map(int index, ButtonHandle button); + INLINE ButtonHandle get_button_map(int index) const; + + INLINE bool get_button_state(int index) const; + INLINE bool is_button_known(int index) const; + +public: + virtual void output(ostream &out) const; + virtual void write(ostream &out, int indent_level = 0) const; + +//////////////////////////////////////////////////////////////////// +// From parent class DataNode +//////////////////////////////////////////////////////////////////// +public: + virtual void + transmit_data(NodeAttributes &data); + + NodeAttributes _attrib; + PT(ButtonEventDataAttribute) _button_events; + + // outputs + static TypeHandle _button_events_type; + +private: + PT(ClientButtonDevice) _button; + +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 "buttonNode.I" + +#endif diff --git a/panda/src/device/clientAnalogDevice.I b/panda/src/device/clientAnalogDevice.I new file mode 100644 index 0000000000..3ac686c77c --- /dev/null +++ b/panda/src/device/clientAnalogDevice.I @@ -0,0 +1,90 @@ +// Filename: clientAnalogDevice.I +// Created by: drose (26Jan01) +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: ClientAnalogDevice::AnalogState::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE ClientAnalogDevice::AnalogState:: +AnalogState() : + _state(0.0), + _known(false) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientAnalogDevice::Constructor +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +INLINE ClientAnalogDevice:: +ClientAnalogDevice(ClientBase *client, const string &device_name): + ClientDevice(client, get_class_type(), device_name) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientAnalogDevice::get_num_controls +// Access: Public +// Description: Returns the number of analog controls known to the +// ClientAnalogDevice. This number may change as +// more controls are discovered. +//////////////////////////////////////////////////////////////////// +INLINE int ClientAnalogDevice:: +get_num_controls() const { + return _controls.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientAnalogDevice::set_control_state +// Access: Public +// Description: Sets the state of the indicated analog index. The +// caller should ensure that lock() is in effect while +// this call is made. This should be a number in the +// range -1.0 to 1.0, representing the current position +// of the control within its total range of movement. +//////////////////////////////////////////////////////////////////// +INLINE void ClientAnalogDevice:: +set_control_state(int index, double state) { + ensure_control_index(index); + nassertv(index >= 0 && index < (int)_controls.size()); + _controls[index]._state = state; + _controls[index]._known = true; +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientAnalogDevice::get_control_state +// Access: Public +// Description: Returns the current position of indicated analog +// control (identified by its index number), or 0.0 if +// the control is unknown. The normal range of a single +// control is -1.0 to 1.0. +//////////////////////////////////////////////////////////////////// +INLINE double ClientAnalogDevice:: +get_control_state(int index) const { + if (index >= 0 && index < (int)_controls.size()) { + return _controls[index]._state; + } else { + return 0.0; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientAnalogDevice::is_control_known +// Access: Public +// Description: Returns true if the state of the indicated analog +// control is known, or false if we have never heard +// anything about this particular control. +//////////////////////////////////////////////////////////////////// +INLINE bool ClientAnalogDevice:: +is_control_known(int index) const { + if (index >= 0 && index < (int)_controls.size()) { + return _controls[index]._known; + } else { + return false; + } +} diff --git a/panda/src/device/clientAnalogDevice.cxx b/panda/src/device/clientAnalogDevice.cxx new file mode 100644 index 0000000000..8718648109 --- /dev/null +++ b/panda/src/device/clientAnalogDevice.cxx @@ -0,0 +1,66 @@ +// Filename: clientAnalogDevice.cxx +// Created by: drose (26Jan01) +// +//////////////////////////////////////////////////////////////////// + +#include "clientAnalogDevice.h" + +#include + +TypeHandle ClientAnalogDevice::_type_handle; + + + +//////////////////////////////////////////////////////////////////// +// Function: ClientAnalogDevice::ensure_control_index +// Access: Private +// Description: Guarantees that there is a slot in the array for the +// indicated index number, by filling the array up to +// that index if necessary. +//////////////////////////////////////////////////////////////////// +void ClientAnalogDevice:: +ensure_control_index(int index) { + nassertv(index >= 0); + + _controls.reserve(index + 1); + while ((int)_controls.size() <= index) { + _controls.push_back(AnalogState()); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientAnalogDevice::write +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void ClientAnalogDevice:: +write(ostream &out, int indent_level) const { + indent(out, indent_level) << get_type() << " " << get_device_name() << ":\n"; + write_controls(out, indent_level + 2); +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientAnalogDevice::write_analogs +// Access: Public +// Description: Writes a multi-line description of the current analog +// control states. +//////////////////////////////////////////////////////////////////// +void ClientAnalogDevice:: +write_controls(ostream &out, int indent_level) const { + bool any_controls = false; + Controls::const_iterator ai; + for (ai = _controls.begin(); ai != _controls.end(); ++ai) { + const AnalogState &state = (*ai); + if (state._known) { + any_controls = true; + + indent(out, indent_level) + << (int)(ai - _controls.begin()) << ". " << state._state << "\n"; + } + } + + if (!any_controls) { + indent(out, indent_level) + << "(no known analog controls)\n"; + } +} diff --git a/panda/src/device/clientAnalogDevice.h b/panda/src/device/clientAnalogDevice.h new file mode 100644 index 0000000000..87cc676a40 --- /dev/null +++ b/panda/src/device/clientAnalogDevice.h @@ -0,0 +1,75 @@ +// Filename: clientAnalogDevice.h +// Created by: drose (26Jan01) +// +//////////////////////////////////////////////////////////////////// + +#ifndef CLIENTANALOGDEVICE_H +#define CLIENTANALOGDEVICE_H + +#include + +#include "clientDevice.h" + +//////////////////////////////////////////////////////////////////// +// Class : ClientAnalogDevice +// Description : A device, attached to the ClientBase by a +// AnalogNode, that records the data from a single +// named analog device. The named device can contain +// any number of analog controls, numbered in +// sequence beginning at zero. +// +// Each analog control returns a value ranging from -1 +// to 1, reflecting the current position of the control +// within its total range of motion. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA ClientAnalogDevice : public ClientDevice { +protected: + INLINE ClientAnalogDevice(ClientBase *client, const string &device_name); + +public: + INLINE int get_num_controls() const; + + INLINE void set_control_state(int index, double state); + INLINE double get_control_state(int index) const; + INLINE bool is_control_known(int index) const; + + virtual void write(ostream &out, int indent_level = 0) const; + void write_controls(ostream &out, int indent_level) const; + +private: + void ensure_control_index(int index); + +protected: + class AnalogState { + public: + INLINE AnalogState(); + + double _state; + bool _known; + }; + + typedef vector Controls; + Controls _controls; + + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + ClientDevice::init_type(); + register_type(_type_handle, "ClientAnalogDevice", + ClientDevice::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#include "clientAnalogDevice.I" + +#endif diff --git a/panda/src/device/clientBase.I b/panda/src/device/clientBase.I new file mode 100644 index 0000000000..9bfc2ac157 --- /dev/null +++ b/panda/src/device/clientBase.I @@ -0,0 +1,49 @@ +// Filename: clientBase.I +// Created by: drose (25Jan01) +// +//////////////////////////////////////////////////////////////////// + + + +//////////////////////////////////////////////////////////////////// +// Function: ClientBase::is_forked +// Access: Public +// Description: Returns true if the ClientBase has been forked (and, +// therefore, poll() does not need to be called), false +// otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool ClientBase:: +is_forked() const { + return _forked; +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientBase::poll +// Access: Public +// Description: Initiates a poll of the client devices, if we are not +// forked and if we have not already polled this frame. +// Returns true if the poll occurred, or false if it did +// not. +//////////////////////////////////////////////////////////////////// +INLINE bool ClientBase:: +poll() { + if (_forked || + _last_poll_frame == ClockObject::get_global_clock()->get_frame_count()) { + return false; + } + + do_poll(); + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientBase::get_last_poll_time +// Access: Public +// Description: Returns the time (according to the global +// ClockObject's get_real_time() method) of the last +// device poll. +//////////////////////////////////////////////////////////////////// +INLINE double ClientBase:: +get_last_poll_time() const { + return _last_poll_time; +} diff --git a/panda/src/device/clientBase.cxx b/panda/src/device/clientBase.cxx index 7a50c5e9d6..177cfe3ddf 100644 --- a/panda/src/device/clientBase.cxx +++ b/panda/src/device/clientBase.cxx @@ -8,18 +8,19 @@ TypeHandle ClientBase::_type_handle; -#include - //////////////////////////////////////////////////////////////////// // Function: ClientBase::constructor -// Access: Public +// Access: Protected // Description: //////////////////////////////////////////////////////////////////// ClientBase:: -ClientBase(const string &server) : - _sleep_time(1000000/60), _server(server), _forked(false) -{ +ClientBase() { + _forked = false; + _last_poll_time = 0.0; + _last_poll_frame = 0; + #ifdef HAVE_IPC + _client_thread = (thread *)NULL; _shutdown = false; #endif } @@ -31,20 +32,22 @@ ClientBase(const string &server) : // Description: //////////////////////////////////////////////////////////////////// ClientBase:: -~ClientBase() -{ -#ifdef HAVE_IPC - if (asynchronous_clients && _forked == true) { - { - //Make sure that you grab all locks before setting shutdown to - //true. This ensures that all polling actions on the thread - //serving the devices have finished before we tell it to - //shutdown - mutex_lock t_lock(_tracker_lock); - mutex_lock a_lock(_analog_lock); - mutex_lock b_lock(_button_lock); - _shutdown = true; +~ClientBase() { + // We have to disconnect all of our devices before destructing. + Devices::iterator di; + Devices devices_copy = _devices; + for (di = devices_copy.begin(); di != devices_copy.end(); ++di) { + DevicesByName &dbn = (*di).second; + DevicesByName::iterator dbni; + for (dbni = dbn.begin(); dbni != dbn.end(); ++dbni) { + ClientDevice *device = (*dbni).second; + device->disconnect(); } + } + +#ifdef HAVE_IPC + if (_forked) { + _shutdown = true; // Join the loader thread - calling process blocks until the loader // thread returns. @@ -53,15 +56,29 @@ ClientBase:: } #endif } + //////////////////////////////////////////////////////////////////// // Function: ClientBase::fork_asynchronous_thread // Access: Public -// Description: +// Description: Forks a separate thread to do all the polling of +// connected devices. The forked thread will poll after +// every poll_time seconds has elapsed. Returns true if +// the fork was successful, or false otherwise (for +// instance, because we were already forked, or because +// asynchronous threads are disabled). //////////////////////////////////////////////////////////////////// -void ClientBase:: -fork_asynchronous_thread(void) { +bool ClientBase:: +fork_asynchronous_thread(double poll_time) { #ifdef HAVE_IPC + if (_forked) { + device_cat.error() + << "Attempt to fork client thread twice.\n"; + return false; + } + if (asynchronous_clients) { + _sleep_time = (int)(1000000 * poll_time); + _client_thread = thread::create(&st_callback, this); _forked = true; if (device_cat.is_debug()) { @@ -69,22 +86,107 @@ fork_asynchronous_thread(void) { << "fork_asynchronous_thread() - forking client thread" << endl; } + return true; } #endif + + return false; } //////////////////////////////////////////////////////////////////// -// Function: ClientBase::set_poll_time +// Function: ClientBase::get_device // Access: Public -// Description: Sets the time between polls. The poll time is assumed -// to be in seconds +// Description: Returns a ClientDevice pointer that corresponds to +// the named device of the indicated device type. The +// device_type should be one of ClientTrackerDevice, +// ClientAnalogDevice, etc.; the device_name is +// implementation defined. +// +// Normally, the user does not need to call this +// function directly; it is called automatically by +// creating a TrackerNode or AnalogNode or some such +// data graph node. +// +// The return value is the pointer to the created device +// (which might be the same pointer returned by a +// previous call to this function with the same +// parameters). When the pointer destructs (i.e. its +// reference count reaches zero) it will automatically +// be disconnected. +// +// If the named device does not exist or cannot be +// connected for some reason, NULL is returned. +//////////////////////////////////////////////////////////////////// +PT(ClientDevice) ClientBase:: +get_device(TypeHandle device_type, const string &device_name) { + DevicesByName &dbn = _devices[device_type]; + + DevicesByName::iterator dbni; + dbni = dbn.find(device_name); + if (dbni != dbn.end()) { + // This device was previously connected. Return it again. + return (*dbni).second; + } + + // We need to create a new device for this name. + PT(ClientDevice) device = make_device(device_type, device_name); + + if (device != (ClientDevice *)NULL) { + dbn.insert(DevicesByName::value_type(device_name, device)); + device->_is_connected = true; + } + + return device; +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientBase::disconnect_device +// Access: Protected, Virtual +// Description: Removes the device, which is presumably about to +// destruct, from the list of connected devices, and +// frees any data required to support it. This device +// will no longer receive automatic updates with each +// poll. +// +// The return value is true if the device was +// disconnected, or false if it was unknown (e.g. it was +// disconnected previously). +//////////////////////////////////////////////////////////////////// +bool ClientBase:: +disconnect_device(TypeHandle device_type, const string &device_name, + ClientDevice *device) { + DevicesByName &dbn = _devices[device_type]; + + DevicesByName::iterator dbni; + dbni = dbn.find(device_name); + if (dbni != dbn.end()) { + if ((*dbni).second == device) { + // We found it! + dbn.erase(dbni); + return true; + } + } + + // The device was unknown. + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientBase::do_poll +// Access: Protected, Virtual +// Description: Implements the polling and updating of connected +// devices, if the ClientBase requires this. This may +// be called in a sub-thread if +// fork_asynchronous_thread() was called; otherwise, it +// will be called once per frame. //////////////////////////////////////////////////////////////////// void ClientBase:: -set_poll_time(float poll_time) { - _sleep_time = (int)(1000000 * poll_time); +do_poll() { + ClockObject *global_clock = ClockObject::get_global_clock(); + _last_poll_frame = global_clock->get_frame_count(); + _last_poll_time = global_clock->get_time(); } - #ifdef HAVE_IPC //////////////////////////////////////////////////////////////////// // Function: ClientBase::st_callback @@ -113,339 +215,13 @@ st_callback(void *arg) { // being watched //////////////////////////////////////////////////////////////////// void ClientBase:: -callback(void) { - while(true) { +callback() { + while (true) { if (_shutdown) { break; } - poll_trackers(); - poll_analogs(); - poll_buttons(); + do_poll(); ipc_traits::sleep(0, _sleep_time); } } #endif // HAVE_IPC - -//////////////////////////////////////////////////////////////////// -// Function: ClientBase::get_tracker_data -// Access: Public, Virtual -// Description: Returns the current data for the sensor of a particular -// tracker -//////////////////////////////////////////////////////////////////// -const TrackerData& ClientBase:: -get_tracker_data(const string &tracker, int sensor) { - - //Very important that this check and associated call are made before - //the mutex lock, otherwise if we are not forked and we lock before - //doing poll we will get into a deadlock condition when the - //associated push for this function is called - if (!_forked) { - poll_tracker(tracker); - } - - //Make sure to prevent simultaneous write and read of device -#ifdef HAVE_IPC - mutex_lock lock(_tracker_lock); -#endif - - if ((find(_trackers.begin(), _trackers.end(), tracker) != _trackers.end()) || - (find(_sensors[tracker].begin(), _sensors[tracker].end(), sensor) - != _sensors[tracker].end())) { - if (_tracker_datas.find(tracker) != _tracker_datas.end()) { - if (_tracker_datas[tracker].find(sensor) != _tracker_datas[tracker].end()) { - return _tracker_datas[tracker][sensor]; - } - } - } - else { - device_cat.error() << "Request for either unknown sensor " << sensor - << " or unknown tracker " << tracker << " made" << endl; - } - - return TrackerData::none(); - -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientBase::get_analog_data -// Access: Public, Virtual -// Description: Returns the current data for the sensor of a particular -// analog -//////////////////////////////////////////////////////////////////// -const AnalogData& ClientBase:: -get_analog_data(const string &analog) { - - //Very important that this check and associated call are made before - //the mutex lock, otherwise if we are not forked and we lock before - //doing poll we will get into a deadlock condition when the - //associated push for this function is called - if (!_forked) { - poll_analog(analog); - } - - //Make sure to prevent simultaneous write and read of device -#ifdef HAVE_IPC - mutex_lock lock(_analog_lock); -#endif - - if (find(_analogs.begin(), _analogs.end(), analog) != _analogs.end()) { - if (_analog_datas.find(analog) != _analog_datas.end()) { - //Make sure to rotate the arrays to ensure access safety - swap(_analog_datas[analog].channels, _analog_datas[analog].stored_channels); - return _analog_datas[analog]; - } - } - else { - device_cat.error() << "Request for unknown analog " << analog << " made" << endl; - } - - return AnalogData::none(); - -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientBase::get_button_data -// Access: Public, Virtual -// Description: Returns the current data for the sensor of a particular -// button -//////////////////////////////////////////////////////////////////// -const ButtonData& ClientBase:: -get_button_data(const string &button) { - - //Very important that this check and associated call are made before - //the mutex lock, otherwise if we are not forked and we lock before - //doing poll we will get into a deadlock condition when the - //associated push for this function is called - if (!_forked) { - poll_button(button); - } - - //Make sure to prevent simultaneous write and read of device -#ifdef HAVE_IPC - mutex_lock lock(_button_lock); -#endif - - if (find(_buttons.begin(), _buttons.end(), button) != _buttons.end()) { - if (_button_datas.find(button) != _button_datas.end()) { - return _button_datas[button]; - } - } - else { - device_cat.error() << "Request for unknown button " << button << " made" << endl; - } - - return ButtonData::none(); - -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientBase::get_dial_data -// Access: Public, Virtual -// Description: Returns the current data for the sensor of a particular -// dial -//////////////////////////////////////////////////////////////////// -const DialData& ClientBase:: -get_dial_data(const string &dial) { - - //Very important that this check and associated call are made before - //the mutex lock, otherwise if we are not forked and we lock before - //doing poll we will get into a deadlock condition when the - //associated push for this function is called - if (!_forked) { - poll_dial(dial); - } - - //Make sure to prevent simultaneous write and read of device -#ifdef HAVE_IPC - mutex_lock lock(_dial_lock); -#endif - - if (find(_dials.begin(), _dials.end(), dial) != _dials.end()) { - if (_dial_datas.find(dial) != _dial_datas.end()) { - return _dial_datas[dial]; - } - } - else { - device_cat.error() << "Request for unknown dial " << dial << " made" << endl; - } - - return DialData::none(); - -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientBase::push_tracker_position -// Access: Protected, Virtual -// Description: Use this function in the children class to fill in -// tracker data -//////////////////////////////////////////////////////////////////// -void ClientBase:: -push_tracker_position(const string &tracker, const int &sensor, const double &ptime, - const LPoint3f &pos, const LVector4f &pquat) { - //Make sure to prevent simultaneous write and read of device -#ifdef HAVE_IPC - mutex_lock lock(_tracker_lock); -#endif - - _tracker_datas[tracker][sensor].ptime = ptime; - _tracker_datas[tracker][sensor].position = pos; - _tracker_datas[tracker][sensor].pquat = pquat; -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientBase::push_tracker_position -// Access: Protected, Virtual -// Description: Use this function in the children class to fill in -// tracker data -//////////////////////////////////////////////////////////////////// -void ClientBase:: -push_tracker_velocity(const string &tracker, int sensor, const double &vtime, - const LPoint3f &vel, const LVector4f &vquat, const float &dt) { - //Make sure to prevent simultaneous write and read of device -#ifdef HAVE_IPC - mutex_lock lock(_tracker_lock); -#endif - - _tracker_datas[tracker][sensor].vtime = vtime; - _tracker_datas[tracker][sensor].velocity = vel; - _tracker_datas[tracker][sensor].vquat = vquat; - _tracker_datas[tracker][sensor].vquat_dt = dt; -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientBase::push_tracker_position -// Access: Protected, Virtual -// Description: Use this function in the children class to fill in -// tracker data -//////////////////////////////////////////////////////////////////// -void ClientBase:: -push_tracker_acceleration(const string &tracker, const int &sensor, const double &atime, - const LPoint3f &acc, const LVector4f &aquat, const float &dt) { - //Make sure to prevent simultaneous write and read of device -#ifdef HAVE_IPC - mutex_lock lock(_tracker_lock); -#endif - - _tracker_datas[tracker][sensor].atime = atime; - _tracker_datas[tracker][sensor].acceleration = acc; - _tracker_datas[tracker][sensor].aquat = aquat; - _tracker_datas[tracker][sensor].aquat_dt = dt; -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientBase::push_analog -// Access: Protected, Virtual -// Description: Use this function in the children class to fill in -// analog data -//////////////////////////////////////////////////////////////////// -void ClientBase:: -push_analog(const string &analog, const float &atime, - const double *channels, int num_channels) { - //Make sure to prevent simultaneous write and read of device -#ifdef HAVE_IPC - mutex_lock lock(_analog_lock); -#endif - - _analog_datas[analog].atime = atime; - - const double *head = channels; - const double *end = head + num_channels; - _analog_datas[analog].stored_channels->clear(); - vector_double::iterator start = _analog_datas[analog].stored_channels->begin(); - _analog_datas[analog].stored_channels->insert(start, head, end); -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientBase::push_button -// Access: Protected, Virtual -// Description: Use this function in the children class to fill in -// button data -//////////////////////////////////////////////////////////////////// -void ClientBase:: -push_button(const string &button, const float &btime, const int &button_id, - const int &state) { - //Make sure to prevent simultaneous write and read of device -#ifdef HAVE_IPC - mutex_lock lock(_button_lock); -#endif - - _button_datas[button].btime = btime; - _button_datas[button].button_id = button_id; - _button_datas[button].state = state; -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientBase::push_dial -// Access: Protected, Virtual -// Description: Use this function in the children class to fill in -// dial data -//////////////////////////////////////////////////////////////////// -void ClientBase:: -push_dial(const string &dial, const float &dtime, const int &dial_id, - const float &change) { - //Make sure to prevent simultaneous write and read of device -#ifdef HAVE_IPC - mutex_lock lock(_dial_lock); -#endif - - _dial_datas[dial].dtime = dtime; - _dial_datas[dial].dial_id = dial_id; - _dial_datas[dial].change = change; -} - - -//////////////////////////////////////////////////////////////////// -// Function: ClientBase::poll_trackers() -// Access: Private -// Description: Polls all current trackers -//////////////////////////////////////////////////////////////////// -void ClientBase:: -poll_trackers() { - Trackers::iterator ti = _trackers.begin(); - for(; ti != _trackers.end(); ti++) { - poll_tracker((*ti)); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientBase::poll_analogs() -// Access: Private -// Description: Polls all current analogs -//////////////////////////////////////////////////////////////////// -void ClientBase:: -poll_analogs() { - Analogs::iterator ti = _analogs.begin(); - for(; ti != _analogs.end(); ti++) { - poll_analog((*ti)); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientBase::poll_buttons() -// Access: Private -// Description: Polls all current buttons -//////////////////////////////////////////////////////////////////// -void ClientBase:: -poll_buttons() { - Buttons::iterator ti = _buttons.begin(); - for(; ti != _buttons.end(); ti++) { - poll_button((*ti)); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientBase::poll_dials() -// Access: Private -// Description: Polls all current dials -//////////////////////////////////////////////////////////////////// -void ClientBase:: -poll_dials() { - Dials::iterator ti = _dials.begin(); - for(; ti != _dials.end(); ti++) { - poll_dial((*ti)); - } -} - - - - diff --git a/panda/src/device/clientBase.h b/panda/src/device/clientBase.h index 4f923800c3..bcd2e41014 100644 --- a/panda/src/device/clientBase.h +++ b/panda/src/device/clientBase.h @@ -3,145 +3,102 @@ // //////////////////////////////////////////////////////////////////// -#ifndef _CLIENT_BASE -#define _CLIENT_BASE +#ifndef CLIENTBASE_H +#define CLIENTBASE_H #include -#include "trackerData.h" -#include "analogData.h" -#include "buttonData.h" -#include "dialData.h" +#include "clientDevice.h" #include #include #include #include +#include +#include #ifdef HAVE_IPC -#include -#include #include #endif #include +//////////////////////////////////////////////////////////////////// +// Class : ClientBase +// Description : An abstract base class for a family of of client +// device interfaces--including trackers, buttons, +// dials, and other analog inputs. +// +// This provides a common interface to connect to such +// devices and extract their data; it is used by +// TrackerNode etc. to put these devices in the data +// graph. +//////////////////////////////////////////////////////////////////// class EXPCL_PANDA ClientBase : public TypedReferenceCount { -PUBLISHED: - ClientBase(const string &server); - ~ClientBase(); - void fork_asynchronous_thread(void); - void set_poll_time(float poll_time); +protected: + ClientBase(); - //ADD FUNCTIONS - virtual bool add_remote_tracker(const string &tracker, int sensor) = 0; - virtual bool add_remote_analog(const string &analog) = 0; - virtual bool add_remote_button(const string &button) = 0; - virtual bool add_remote_dial(const string &dial) = 0; +PUBLISHED: + ~ClientBase(); + + bool fork_asynchronous_thread(double poll_time); + INLINE bool is_forked() const; + INLINE bool poll(); + INLINE double get_last_poll_time() const; public: - //GET FUNCTIONS - virtual const TrackerData &get_tracker_data(const string &tracker, int sensor); - virtual const AnalogData &get_analog_data(const string &analog); - virtual const ButtonData &get_button_data(const string &button); - virtual const DialData &get_dial_data(const string &dial); - + PT(ClientDevice) get_device(TypeHandle device_type, + const string &device_name); + protected: - void push_tracker_position(const string &tracker, const int &sensor, const double &ptime, - const LPoint3f &pos, const LVector4f &pquat); - void push_tracker_velocity(const string &tracker, int sensor, const double &vtime, - const LPoint3f &vel, const LVector4f &vquat, const float &dt); - void push_tracker_acceleration(const string &tracker, const int &sensor, const double &atime, - const LPoint3f &acc, const LVector4f &aquat, const float &dt); + virtual PT(ClientDevice) make_device(TypeHandle device_type, + const string &device_name)=0; - void push_analog(const string &analog, const float &atime, - const double *channels, int num_channels); - void push_button(const string &button, const float &btime, const int &button_id, - const int &state); - void push_dial(const string &dial, const float &dtime, const int &dial_id, - const float &change); + virtual bool disconnect_device(TypeHandle device_type, + const string &device_name, + ClientDevice *device); + + virtual void do_poll(); private: - int _sleep_time; - const string _server; + typedef map DevicesByName; + typedef map Devices; + Devices _devices; + bool _forked; + double _last_poll_time; + int _last_poll_frame; #ifdef HAVE_IPC - //Device locks and conditionals - mutex _tracker_lock; - mutex _analog_lock; - mutex _button_lock; - mutex _dial_lock; - - //Thread variables and functions + int _sleep_time; thread *_client_thread; bool _shutdown; static void* st_callback(void *arg); - void callback(void); + void callback(); #endif -protected: - //Device polling functions - void poll_trackers(); - virtual void poll_tracker(const string &tracker) = 0; - - void poll_analogs(); - virtual void poll_analog(const string &analog) = 0; - virtual int max_analog_channels(void) = 0; - - void poll_buttons(); - virtual void poll_button(const string &button) = 0; - - void poll_dials(); - virtual void poll_dial(const string &dial) = 0; - - -protected: - typedef map< int, TrackerData > SensorDatas; - typedef map< const string, SensorDatas > TrackerDatas; - typedef map< const string, AnalogData > AnalogDatas; - typedef map< const string, ButtonData > ButtonDatas; - typedef map< const string, DialData > DialDatas; - - typedef vector_string Trackers; - typedef vector_int Sensors; - typedef map< string, Sensors > TrackerSensors; - typedef vector_string Analogs; - typedef vector_string Buttons; - typedef vector_string Dials; - - TrackerDatas _tracker_datas; - Trackers _trackers; - TrackerSensors _sensors; - - AnalogDatas _analog_datas; - Analogs _analogs; - - ButtonDatas _button_datas; - Buttons _buttons; - - DialDatas _dial_datas; - Dials _dials; public: - static TypeHandle get_class_type( void ) { - return _type_handle; + static TypeHandle get_class_type() { + return _type_handle; } - static void init_type( void ) { + static void init_type() { TypedReferenceCount::init_type(); - register_type( _type_handle, "ClientBase", - TypedReferenceCount::get_class_type() ); + register_type(_type_handle, "ClientBase", + TypedReferenceCount::get_class_type()); } - virtual TypeHandle get_type( void ) const { + virtual TypeHandle get_type() const { return get_class_type(); } - virtual TypeHandle force_init_type() { - init_type(); - return get_class_type(); - } - + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + private: - static TypeHandle _type_handle; + static TypeHandle _type_handle; + + friend class ClientDevice; }; + +#include "clientBase.I" + #endif diff --git a/panda/src/device/clientButtonDevice.I b/panda/src/device/clientButtonDevice.I new file mode 100644 index 0000000000..b2a09cbcfd --- /dev/null +++ b/panda/src/device/clientButtonDevice.I @@ -0,0 +1,115 @@ +// Filename: clientButtonDevice.I +// Created by: drose (26Jan01) +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: ClientButtonDevice::ButtonState::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE ClientButtonDevice::ButtonState:: +ButtonState() : + _handle(ButtonHandle::none()), + _state(S_unknown) +{ +} + + +//////////////////////////////////////////////////////////////////// +// Function: ClientButtonDevice::get_num_buttons +// Access: Public +// Description: Returns the number of buttons known to the +// ClientButtonDevice. This includes those buttons +// whose state has been seen, as well as buttons that +// have been associated with a ButtonHandle even if +// their state is unknown. This number may change as +// more buttons are discovered. +//////////////////////////////////////////////////////////////////// +INLINE int ClientButtonDevice:: +get_num_buttons() const { + return _buttons.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientButtonDevice::set_button_map +// Access: Public +// Description: Associates the indicated ButtonHandle with the button +// of the indicated index number. When the given button +// index changes state, a corresponding ButtonEvent will +// be generated with the given ButtonHandle. Pass +// ButtonHandle::none() to turn off any association. +// +// It is not necessary to call this if you simply want +// to query the state of the various buttons by index +// number; this is only necessary in order to generate +// ButtonEvents when the buttons change state. +//////////////////////////////////////////////////////////////////// +INLINE void ClientButtonDevice:: +set_button_map(int index, ButtonHandle button) { + ensure_button_index(index); + nassertv(index >= 0 && index < (int)_buttons.size()); + _buttons[index]._handle = button; +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientButtonDevice::get_button_map +// Access: Public +// Description: Returns the ButtonHandle that was previously +// associated with the given index number by +// a call to set_button_map(), or ButtonHandle::none() +// if no button was associated. +//////////////////////////////////////////////////////////////////// +INLINE ButtonHandle ClientButtonDevice:: +get_button_map(int index) const { + if (index >= 0 && index < (int)_buttons.size()) { + return _buttons[index]._handle; + } else { + return ButtonHandle::none(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientButtonDevice::get_button_state +// Access: Public +// Description: Returns true if the indicated button (identified by +// its index number) is currently known to be down, or +// false if it is up or unknown. +//////////////////////////////////////////////////////////////////// +INLINE bool ClientButtonDevice:: +get_button_state(int index) const { + if (index >= 0 && index < (int)_buttons.size()) { + return (_buttons[index]._state == S_down); + } else { + return false; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientButtonDevice::is_button_known +// Access: Public +// Description: Returns true if the state of the indicated button is +// known, or false if we have never heard anything about +// this particular button. +//////////////////////////////////////////////////////////////////// +INLINE bool ClientButtonDevice:: +is_button_known(int index) const { + if (index >= 0 && index < (int)_buttons.size()) { + return _buttons[index]._state != S_unknown; + } else { + return false; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientButtonDevice::get_button_events +// Access: Public +// Description: Returns the list of recently-generated ButtonEvents. +// This must be periodically cleared, or the buttons +// will accumulate. +//////////////////////////////////////////////////////////////////// +INLINE ButtonEventDataAttribute *ClientButtonDevice:: +get_button_events() const { + return _button_events; +} diff --git a/panda/src/device/clientButtonDevice.cxx b/panda/src/device/clientButtonDevice.cxx new file mode 100644 index 0000000000..5bbeeae382 --- /dev/null +++ b/panda/src/device/clientButtonDevice.cxx @@ -0,0 +1,153 @@ +// Filename: clientButtonDevice.cxx +// Created by: drose (26Jan01) +// +//////////////////////////////////////////////////////////////////// + +#include "clientButtonDevice.h" + +#include + +TypeHandle ClientButtonDevice::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: ClientButtonDevice::Constructor +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +ClientButtonDevice:: +ClientButtonDevice(ClientBase *client, const string &device_name): + ClientDevice(client, get_class_type(), device_name) +{ + _button_events = new ButtonEventDataAttribute(); +} + + +//////////////////////////////////////////////////////////////////// +// Function: ClientButtonDevice::set_button_state +// Access: Public +// Description: Sets the state of the indicated button index, where +// true indicates down, and false indicates up. This +// may generate a ButtonEvent if the button has an +// associated ButtonHandle. The caller should ensure +// that lock() is in effect while this call is made. +//////////////////////////////////////////////////////////////////// +void ClientButtonDevice:: +set_button_state(int index, bool down) { + ensure_button_index(index); + nassertv(index >= 0 && index < (int)_buttons.size()); + _buttons[index]._state = down ? S_down : S_up; + + ButtonHandle handle = _buttons[index]._handle; + if (handle != ButtonHandle::none()) { + _button_events->push_back(ButtonEvent(handle, down)); + } +} + + +//////////////////////////////////////////////////////////////////// +// Function: ClientButtonDevice::ensure_button_index +// Access: Private +// Description: Guarantees that there is a slot in the array for the +// indicated index number, by filling the array up to +// that index if necessary. +//////////////////////////////////////////////////////////////////// +void ClientButtonDevice:: +ensure_button_index(int index) { + nassertv(index >= 0); + + _buttons.reserve(index + 1); + while ((int)_buttons.size() <= index) { + _buttons.push_back(ButtonState()); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientButtonDevice::output +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void ClientButtonDevice:: +output(ostream &out) const { + out << get_type() << " " << get_device_name() << " ("; + output_buttons(out); + out << ")"; +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientButtonDevice::write +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void ClientButtonDevice:: +write(ostream &out, int indent_level) const { + indent(out, indent_level) << get_type() << " " << get_device_name() << ":\n"; + write_buttons(out, indent_level + 2); +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientButtonDevice::output_buttons +// Access: Public +// Description: Writes a one-line string of all of the current button +// states. +//////////////////////////////////////////////////////////////////// +void ClientButtonDevice:: +output_buttons(ostream &out) const { + bool any_buttons = false; + Buttons::const_iterator bi; + for (bi = _buttons.begin(); bi != _buttons.end(); ++bi) { + const ButtonState &state = (*bi); + if (state._state != S_unknown) { + if (any_buttons) { + out << ", "; + } + any_buttons = true; + out << (int)(bi - _buttons.begin()) << "="; + if (state._state == S_up) { + out << "up"; + } else { + out << "down"; + } + } + } + + if (!any_buttons) { + out << "no known buttons"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientButtonDevice::write_buttons +// Access: Public +// Description: Writes a multi-line description of the current button +// states. +//////////////////////////////////////////////////////////////////// +void ClientButtonDevice:: +write_buttons(ostream &out, int indent_level) const { + bool any_buttons = false; + Buttons::const_iterator bi; + for (bi = _buttons.begin(); bi != _buttons.end(); ++bi) { + const ButtonState &state = (*bi); + if (state._state != S_unknown) { + any_buttons = true; + + indent(out, indent_level) + << (int)(bi - _buttons.begin()) << ". "; + + if (state._handle != ButtonHandle::none()) { + out << "(" << state._handle << ") "; + } + + if (state._state == S_up) { + out << "up"; + } else { + out << "down"; + } + out << "\n"; + } + } + + if (!any_buttons) { + indent(out, indent_level) + << "(no known buttons)\n"; + } +} diff --git a/panda/src/device/clientButtonDevice.h b/panda/src/device/clientButtonDevice.h new file mode 100644 index 0000000000..df7bbde363 --- /dev/null +++ b/panda/src/device/clientButtonDevice.h @@ -0,0 +1,92 @@ +// Filename: clientButtonDevice.h +// Created by: drose (26Jan01) +// +//////////////////////////////////////////////////////////////////// + +#ifndef CLIENTBUTTONDEVICE_H +#define CLIENTBUTTONDEVICE_H + +#include + +#include "clientDevice.h" + +#include +#include +#include + +//////////////////////////////////////////////////////////////////// +// Class : ClientButtonDevice +// Description : A device, attached to the ClientBase by a +// ButtonNode, that records the data from a single +// named button device. The named device can contain +// any number of up/down style buttons, numbered in +// sequence beginning at zero; these are mapped by this +// class to a sequence of ButtonHandles specified by the +// user. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA ClientButtonDevice : public ClientDevice { +protected: + ClientButtonDevice(ClientBase *client, const string &device_name); + +public: + INLINE int get_num_buttons() const; + + INLINE void set_button_map(int index, ButtonHandle button); + INLINE ButtonHandle get_button_map(int index) const; + + void set_button_state(int index, bool down); + INLINE bool get_button_state(int index) const; + INLINE bool is_button_known(int index) const; + + INLINE ButtonEventDataAttribute *get_button_events() const; + + virtual void output(ostream &out) const; + virtual void write(ostream &out, int indent_level = 0) const; + + void output_buttons(ostream &out) const; + void write_buttons(ostream &out, int indent_level) const; + +private: + void ensure_button_index(int index); + +protected: + enum State { + S_unknown, + S_up, + S_down + }; + + class ButtonState { + public: + INLINE ButtonState(); + + ButtonHandle _handle; + State _state; + }; + + typedef vector Buttons; + Buttons _buttons; + + PT(ButtonEventDataAttribute) _button_events; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + ClientDevice::init_type(); + register_type(_type_handle, "ClientButtonDevice", + ClientDevice::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#include "clientButtonDevice.I" + +#endif diff --git a/panda/src/device/clientDevice.I b/panda/src/device/clientDevice.I new file mode 100644 index 0000000000..83c91c518f --- /dev/null +++ b/panda/src/device/clientDevice.I @@ -0,0 +1,85 @@ +// Filename: clientDevice.I +// Created by: drose (25Jan01) +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: ClientDevice::get_client +// Access: Public +// Description: Returns the ClientBase this device is associated +// with. +//////////////////////////////////////////////////////////////////// +INLINE ClientBase *ClientDevice:: +get_client() const { + return _client; +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientDevice::is_connected +// Access: Public +// Description: Returns true if the device is still connected to its +// ClientBase, false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool ClientDevice:: +is_connected() const { + return _is_connected; +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientDevice::get_device_type +// Access: Public +// Description: Returns the type of device this is considered to be +// to the ClientBase: a ClientTrackerDevice, +// ClientAnalogDevice, or what have you. This is not +// exactly the same thing as get_type(), because it does +// not return the exact type of the ClientDevice +// (e.g. it reports ClientTrackerDevice, not +// VrpnTrackerDevice). +//////////////////////////////////////////////////////////////////// +INLINE TypeHandle ClientDevice:: +get_device_type() const { + return _device_type; +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientDevice::get_device_name +// Access: Public +// Description: Returns the device name reported to the ClientBase. +// This has some implementation-defined meaning to +// identify particular devices. +//////////////////////////////////////////////////////////////////// +INLINE const string &ClientDevice:: +get_device_name() const { + return _device_name; +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientDevice::lock +// Access: Public +// Description: Grabs the mutex associated with this particular +// device. The device will not update asynchronously +// while the mutex is held, allowing the user to copy +// the data out without fear of getting a partial update +// during the copy. +//////////////////////////////////////////////////////////////////// +INLINE void ClientDevice:: +lock() { +#ifdef HAVE_IPC + _lock.lock(); +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientDevice::unlock +// Access: Public +// Description: Releases the mutex associated with this particular +// device. This should be called after all the data has +// been successfully copied out. See lock(). +//////////////////////////////////////////////////////////////////// +INLINE void ClientDevice:: +unlock() { +#ifdef HAVE_IPC + _lock.unlock(); +#endif +} diff --git a/panda/src/device/clientDevice.cxx b/panda/src/device/clientDevice.cxx new file mode 100644 index 0000000000..2ca621ecc4 --- /dev/null +++ b/panda/src/device/clientDevice.cxx @@ -0,0 +1,104 @@ +// Filename: clientDevice.cxx +// Created by: drose (25Jan01) +// +//////////////////////////////////////////////////////////////////// + +#include "clientDevice.h" +#include "clientBase.h" + +#include + +TypeHandle ClientDevice::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: ClientDevice::Constructor +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +ClientDevice:: +ClientDevice(ClientBase *client, TypeHandle device_type, + const string &device_name) : + _client(client), + _device_type(device_type), + _device_name(device_name) +{ + // We have to explicitly ref the client pointer, since we can't use + // a PT(ClientBase) for circular include reasons. + _client->ref(); + _is_connected = false; +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientDevice::Destructor +// Access: Public, Virtual +// Description: We don't actually call disconnect() at the +// ClientDevice level destructor, because by the time +// we get here we're already partly destructed. +// Instead, we should call disconnect() from each +// specific kind of derived class. +//////////////////////////////////////////////////////////////////// +ClientDevice:: +~ClientDevice() { + nassertv(!_is_connected); + + // And now we explicitly unref the client pointer. + unref_delete(_client); +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientDevice::disconnect +// Access: Public +// Description: Disconnects the ClientDevice from its ClientBase +// object. The device will stop receiving +// updates. +// +// Normally, you should not need to call this explicitly +// (and it is probably a mistake to do so); it will +// automatically be called when the ClientDevice object +// destructs. +//////////////////////////////////////////////////////////////////// +void ClientDevice:: +disconnect() { + if (_is_connected) { + bool disconnected = + _client->disconnect_device(_device_type, _device_name, this); + _is_connected = false; + nassertv(disconnected); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientDevice::poll +// Access: Public +// Description: Causes the connected ClientBase to poll all of its +// clients, if necessary. This will be a no-op if the +// client is running in forked mode, or if it has +// already polled everything this frame. +// +// This should generally be called before accessing the +// data in this ClientDevice to ensure that it is fresh. +//////////////////////////////////////////////////////////////////// +void ClientDevice:: +poll() { + _client->poll(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientDevice::output +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void ClientDevice:: +output(ostream &out) const { + out << get_type() << " " << get_device_name(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientDevice::write +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void ClientDevice:: +write(ostream &out, int indent_level) const { + indent(out, indent_level) << *this << "\n"; +} diff --git a/panda/src/device/clientDevice.h b/panda/src/device/clientDevice.h new file mode 100644 index 0000000000..f761efd57c --- /dev/null +++ b/panda/src/device/clientDevice.h @@ -0,0 +1,85 @@ +// Filename: clientDevice.h +// Created by: drose (25Jan01) +// +//////////////////////////////////////////////////////////////////// + +#ifndef CLIENTDEVICE_H +#define CLIENTDEVICE_H + +#include + +#include + +#ifdef HAVE_IPC +#include +#endif + +class ClientBase; + +//////////////////////////////////////////////////////////////////// +// Class : ClientDevice +// Description : Any of a number of different devices that might be +// attached to a ClientBase, including trackers, etc. +// This is an abstract interface; the actual +// implementations are in ClientTrackerDevice, etc. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA ClientDevice : public TypedReferenceCount { +protected: + ClientDevice(ClientBase *client, TypeHandle device_type, + const string &device_name); + +public: + virtual ~ClientDevice(); + + INLINE ClientBase *get_client() const; + INLINE TypeHandle get_device_type() const; + INLINE const string &get_device_name() const; + + INLINE bool is_connected() const; + void disconnect(); + + void poll(); + INLINE void lock(); + INLINE void unlock(); + + virtual void output(ostream &out) const; + virtual void write(ostream &out, int indent_level = 0) const; + +private: + ClientBase *_client; + TypeHandle _device_type; + string _device_name; + bool _is_connected; + +#ifdef HAVE_IPC + mutex _lock; +#endif + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + TypedReferenceCount::init_type(); + register_type(_type_handle, "ClientDevice", + TypedReferenceCount::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; + + friend class ClientBase; +}; + +INLINE ostream &operator <<(ostream &out, const ClientDevice &device) { + device.output(out); + return out; +} + +#include "clientDevice.I" + +#endif diff --git a/panda/src/device/clientTrackerDevice.I b/panda/src/device/clientTrackerDevice.I new file mode 100644 index 0000000000..c49e1cc64e --- /dev/null +++ b/panda/src/device/clientTrackerDevice.I @@ -0,0 +1,28 @@ +// Filename: clientTrackerDevice.I +// Created by: drose (25Jan01) +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: ClientTrackerDevice::Constructor +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +INLINE ClientTrackerDevice:: +ClientTrackerDevice(ClientBase *client, const string &device_name): + ClientDevice(client, get_class_type(), device_name) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: ClientTrackerDevice::get_data +// Access: Public +// Description: Returns the TrackerData that this device is +// reporting. +//////////////////////////////////////////////////////////////////// +INLINE const TrackerData &ClientTrackerDevice:: +get_data() const { + return _data; +} + diff --git a/panda/src/device/clientTrackerDevice.cxx b/panda/src/device/clientTrackerDevice.cxx new file mode 100644 index 0000000000..976b406b5e --- /dev/null +++ b/panda/src/device/clientTrackerDevice.cxx @@ -0,0 +1,8 @@ +// Filename: clientTrackerDevice.cxx +// Created by: drose (25Jan01) +// +//////////////////////////////////////////////////////////////////// + +#include "clientTrackerDevice.h" + +TypeHandle ClientTrackerDevice::_type_handle; diff --git a/panda/src/device/clientTrackerDevice.h b/panda/src/device/clientTrackerDevice.h new file mode 100644 index 0000000000..29b0da9d60 --- /dev/null +++ b/panda/src/device/clientTrackerDevice.h @@ -0,0 +1,50 @@ +// Filename: clientTrackerDevice.h +// Created by: drose (25Jan01) +// +//////////////////////////////////////////////////////////////////// + +#ifndef CLIENTTRACKERDEVICE_H +#define CLIENTTRACKERDEVICE_H + +#include + +#include "clientDevice.h" +#include "trackerData.h" + +//////////////////////////////////////////////////////////////////// +// Class : ClientTrackerDevice +// Description : A device, attached to the ClientBase by a +// TrackerNode, that records the data from a single +// tracker device. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA ClientTrackerDevice : public ClientDevice { +protected: + INLINE ClientTrackerDevice(ClientBase *client, const string &device_name); + +public: + INLINE const TrackerData &get_data() const; + +protected: + TrackerData _data; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + ClientDevice::init_type(); + register_type(_type_handle, "ClientTrackerDevice", + ClientDevice::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#include "clientTrackerDevice.I" + +#endif diff --git a/panda/src/device/config_device.cxx b/panda/src/device/config_device.cxx index bab3b9d59f..d7de000366 100644 --- a/panda/src/device/config_device.cxx +++ b/panda/src/device/config_device.cxx @@ -4,10 +4,15 @@ //////////////////////////////////////////////////////////////////// #include "config_device.h" -#include "mouse.h" +#include "analogNode.h" +#include "buttonNode.h" +#include "clientAnalogDevice.h" #include "clientBase.h" +#include "clientButtonDevice.h" +#include "clientDevice.h" +#include "clientTrackerDevice.h" +#include "mouse.h" #include "trackerNode.h" -#include "adinputNode.h" #include @@ -36,8 +41,13 @@ init_libdevice() { } initialized = true; + AnalogNode::init_type(); + ButtonNode::init_type(); + ClientAnalogDevice::init_type(); + ClientBase::init_type(); + ClientButtonDevice::init_type(); + ClientDevice::init_type(); + ClientTrackerDevice::init_type(); MouseAndKeyboard::init_type(); TrackerNode::init_type(); - ADInputNode::init_type(); - ClientBase::init_type(); } diff --git a/panda/src/device/trackerData.I b/panda/src/device/trackerData.I index f7d749ab91..85b7494fb2 100644 --- a/panda/src/device/trackerData.I +++ b/panda/src/device/trackerData.I @@ -10,7 +10,7 @@ //////////////////////////////////////////////////////////////////// INLINE TrackerData:: TrackerData() : - ptime(0), vtime(0), vquat_dt(0), atime(0), aquat_dt(0) + _flags(0) { } @@ -25,35 +25,176 @@ TrackerData(const TrackerData ©) { } //////////////////////////////////////////////////////////////////// -// Function: TrackerData::Copy Assignment Operator +// Function: TrackerData::clear // Access: Public -// Description: +// Description: Removes all data from the structure. //////////////////////////////////////////////////////////////////// -INLINE TrackerData &TrackerData:: -operator = (const TrackerData ©) { - ptime = copy.ptime; - position = copy.position; - pquat = copy.pquat; - - vtime = copy.vtime; - velocity = copy.velocity; - vquat = copy.vquat; - vquat_dt = copy.vquat_dt; - - atime = copy.atime; - acceleration = copy.acceleration; - aquat = copy.aquat; - aquat_dt = copy.aquat_dt; - - return *this; +INLINE void TrackerData:: +clear() { + _flags = 0; } //////////////////////////////////////////////////////////////////// -// Function: TrackerData::none -// Access: Public, Static -// Description: Returns an empty TrackerData object +// Function: TrackerData::set_time +// Access: Public +// Description: Indicates the time at which the position information +// (pos and orient) are effective. This is a time +// elapsed in seconds since some undefined epoch; it may +// or may not correspond to the clock time indicated in +// the global ClockObject. //////////////////////////////////////////////////////////////////// -INLINE const TrackerData &TrackerData:: -none() { - return _none; +INLINE void TrackerData:: +set_time(double time) { + _time = time; + _flags |= F_has_time; +} + +//////////////////////////////////////////////////////////////////// +// Function: TrackerData::has_time +// Access: Public +// Description: Returns true if the position information time is +// available. See set_time(). +//////////////////////////////////////////////////////////////////// +INLINE bool TrackerData:: +has_time() const { + return (_flags & F_has_time) != 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: TrackerData::get_time +// Access: Public +// Description: Returns the time at which the position information +// (pos and orient) are effective. It is an error to +// call this if has_time() does not return true. See +// set_time(). +//////////////////////////////////////////////////////////////////// +INLINE double TrackerData:: +get_time() const { + nassertr(has_time(), 0.0); + return _time; +} + +//////////////////////////////////////////////////////////////////// +// Function: TrackerData::set_pos +// Access: Public +// Description: Indicates the current position of the tracker sensor +// in space. The coordinate system of this position is +// defined by the tracker. +//////////////////////////////////////////////////////////////////// +INLINE void TrackerData:: +set_pos(const LPoint3f &pos) { + _pos = pos; + _flags |= F_has_pos; +} + +//////////////////////////////////////////////////////////////////// +// Function: TrackerData::has_pos +// Access: Public +// Description: Returns true if the current position is available. +// See set_pos(). +//////////////////////////////////////////////////////////////////// +INLINE bool TrackerData:: +has_pos() const { + return (_flags & F_has_pos) != 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: TrackerData::get_pos +// Access: Public +// Description: Returns the current position of the tracker. It is +// legal to call this if has_pos() returns false; in +// this case, the position will always be (0, 0, 0). +//////////////////////////////////////////////////////////////////// +INLINE const LPoint3f &TrackerData:: +get_pos() const { + if (has_pos()) { + return _pos; + } else { + static LPoint3f zero(0.0, 0.0, 0.0); + return zero; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TrackerData::set_orient +// Access: Public +// Description: Indicates the current orientation of the tracker +// sensor in space. The coordinate system of this +// orientation is defined by the tracker, but should be +// the same coordinate system as that reflected by +// set_pos(). +//////////////////////////////////////////////////////////////////// +INLINE void TrackerData:: +set_orient(const LOrientationf &orient) { + _orient = orient; + _flags |= F_has_orient; +} + +//////////////////////////////////////////////////////////////////// +// Function: TrackerData::has_orient +// Access: Public +// Description: Returns true if the current orientation is available. +// See set_orient(). +//////////////////////////////////////////////////////////////////// +INLINE bool TrackerData:: +has_orient() const { + return (_flags & F_has_orient) != 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: TrackerData::get_orient +// Access: Public +// Description: Returns the current orientation of the tracker. It +// is legal to call this if has_orient() returns false; +// in this case, the result is always the identity +// orientation. +//////////////////////////////////////////////////////////////////// +INLINE const LOrientationf &TrackerData:: +get_orient() const { + if (has_orient()) { + return _orient; + } else { + static LOrientationf ident = LOrientationf::ident_quat(); + return ident; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TrackerData::set_dt +// Access: Public +// Description: Indicates the amount of elapsed time over which which +// the information (pos and orient) were computed. This +// only makes sense if the information represents +// velocity or acceleration, rather than position. This +// is an elapsed time in seconds. +//////////////////////////////////////////////////////////////////// +INLINE void TrackerData:: +set_dt(double dt) { + _dt = dt; + _flags |= F_has_dt; +} + +//////////////////////////////////////////////////////////////////// +// Function: TrackerData::has_dt +// Access: Public +// Description: Returns true if the computed elapsed time is +// available. See set_dt(). +//////////////////////////////////////////////////////////////////// +INLINE bool TrackerData:: +has_dt() const { + return (_flags & F_has_dt) != 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: TrackerData::get_dt +// Access: Public +// Description: Returns the amount of elapsed time over which the +// information (pos and orient) were computed. It +// is an error to call this if has_dt() does not return +// true. See set_dt(). +//////////////////////////////////////////////////////////////////// +INLINE double TrackerData:: +get_dt() const { + nassertr(has_dt(), 0.0); + return _dt; } diff --git a/panda/src/device/trackerData.cxx b/panda/src/device/trackerData.cxx index f6cc9917e9..73cd23d897 100644 --- a/panda/src/device/trackerData.cxx +++ b/panda/src/device/trackerData.cxx @@ -5,5 +5,17 @@ #include "trackerData.h" -// This is initialized to zero by static initialization. -TrackerData TrackerData::_none; +//////////////////////////////////////////////////////////////////// +// Function: TrackerData::Copy Assignment Operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void TrackerData:: +operator = (const TrackerData ©) { + _flags = copy._flags; + + _time = copy._time; + _pos = copy._pos; + _orient = copy._orient; + _dt = copy._dt; +} diff --git a/panda/src/device/trackerData.h b/panda/src/device/trackerData.h index bfd474138b..7ee8cf2bf3 100644 --- a/panda/src/device/trackerData.h +++ b/panda/src/device/trackerData.h @@ -3,36 +3,54 @@ // //////////////////////////////////////////////////////////////////// -#ifndef TRACKER_DATA -#define TRACKER_DATA +#ifndef TRACKERDATA_H +#define TRACKERDATA_H #include #include +//////////////////////////////////////////////////////////////////// +// Class : TrackerData +// Description : Stores the kinds of data that a tracker might output. +//////////////////////////////////////////////////////////////////// class EXPCL_PANDA TrackerData { public: INLINE TrackerData(); INLINE TrackerData(const TrackerData ©); - INLINE TrackerData &operator = (const TrackerData ©); + void operator = (const TrackerData ©); - INLINE static const TrackerData &none(); + INLINE void clear(); - double ptime; - LPoint3f position; - LVector4f pquat; - - double vtime; - LVector3f velocity; - LVector4f vquat; - float vquat_dt; + INLINE void set_time(double time); + INLINE bool has_time() const; + INLINE double get_time() const; - double atime; - LVector3f acceleration; - LVector4f aquat; - float aquat_dt; + INLINE void set_pos(const LPoint3f &pos); + INLINE bool has_pos() const; + INLINE const LPoint3f &get_pos() const; + + INLINE void set_orient(const LOrientationf &orient); + INLINE bool has_orient() const; + INLINE const LOrientationf &get_orient() const; + + INLINE void set_dt(double dt); + INLINE bool has_dt() const; + INLINE double get_dt() const; private: - static TrackerData _none; + enum Flags { + F_has_time = 0x0001, + F_has_pos = 0x0002, + F_has_orient = 0x0004, + F_has_dt = 0x0008, + }; + + int _flags; + + double _time; + LPoint3f _pos; + LOrientationf _orient; + double _dt; }; #include "trackerData.I" diff --git a/panda/src/device/trackerNode.I b/panda/src/device/trackerNode.I new file mode 100644 index 0000000000..15316b2747 --- /dev/null +++ b/panda/src/device/trackerNode.I @@ -0,0 +1,51 @@ +// Filename: trackerNode.I +// Created by: drose (25Jan01) +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: TrackerNode::is_valid +// Access: Public +// Description: Returns true if the TrackerNode is valid and +// connected to a server, false otherwise. +//////////////////////////////////////////////////////////////////// +bool TrackerNode:: +is_valid() const { + return (_tracker != (ClientTrackerDevice *)NULL) && _tracker->is_connected(); +} + + +//////////////////////////////////////////////////////////////////// +// Function: TrackerNode::get_pos +// Access: Public +// Description: Returns the current position of the tracker, if it is +// available. +//////////////////////////////////////////////////////////////////// +const LPoint3f &TrackerNode:: +get_pos() const { + return _data.get_pos(); +} + +//////////////////////////////////////////////////////////////////// +// Function: TrackerNode::get_orient +// Access: Public +// Description: Returns the current orientation of the tracker, if it +// is available. +//////////////////////////////////////////////////////////////////// +const LOrientationf &TrackerNode:: +get_orient() const { + return _data.get_orient(); +} + +//////////////////////////////////////////////////////////////////// +// Function: TrackerNode::get_transform +// Access: Public +// Description: Returns the current position and orientation of the +// tracker, as a combined matrix. +//////////////////////////////////////////////////////////////////// +const LMatrix4f &TrackerNode:: +get_transform() const { + return _transform; +} + diff --git a/panda/src/device/trackerNode.cxx b/panda/src/device/trackerNode.cxx index 85bc188897..845098fe7f 100644 --- a/panda/src/device/trackerNode.cxx +++ b/panda/src/device/trackerNode.cxx @@ -11,19 +11,7 @@ //////////////////////////////////////////////////////////////////// TypeHandle TrackerNode::_type_handle; -TypeHandle TrackerNode::_ptime_type; -TypeHandle TrackerNode::_position_type; -TypeHandle TrackerNode::_pquat_type; - -TypeHandle TrackerNode::_vtime_type; -TypeHandle TrackerNode::_velocity_type; -TypeHandle TrackerNode::_vquat_type; -TypeHandle TrackerNode::_vquat_dt_type; - -TypeHandle TrackerNode::_atime_type; -TypeHandle TrackerNode::_acceleration_type; -TypeHandle TrackerNode::_aquat_type; -TypeHandle TrackerNode::_aquat_dt_type; +TypeHandle TrackerNode::_transform_type; //////////////////////////////////////////////////////////////////// // Function: TrackerNode::Constructor @@ -31,39 +19,44 @@ TypeHandle TrackerNode::_aquat_dt_type; // Description: //////////////////////////////////////////////////////////////////// TrackerNode:: -TrackerNode(PT(ClientBase) client, const string &tracker, - int sensor) : - DataNode(tracker), _client(client), _tracker(tracker), _sensor(sensor) +TrackerNode(ClientBase *client, const string &device_name) : + DataNode(device_name) { - _client->add_remote_tracker(_tracker, _sensor); - - _ptime = new DoubleDataAttribute(); - _position = new Vec3DataAttribute(LPoint3f(0,0,0)); - _pquat = new Vec4DataAttribute(LVector4f(0,0,0,0)); + nassertv(client != (ClientBase *)NULL); + PT(ClientDevice) device = + client->get_device(ClientTrackerDevice::get_class_type(), device_name); - _vtime = new DoubleDataAttribute(); - _velocity = new Vec3DataAttribute(LPoint3f(0,0,0)); - _vquat = new Vec4DataAttribute(LVector4f(0,0,0,0)); - _vquat_dt = new DoubleDataAttribute(); + if (device == (ClientDevice *)NULL) { + device_cat.warning() + << "Unable to open tracker device " << device_name << "\n"; + return; + } - _atime = new DoubleDataAttribute(); - _acceleration = new Vec3DataAttribute(LPoint3f(0,0,0)); - _aquat = new Vec4DataAttribute(LVector4f(0,0,0,0)); - _aquat_dt = new DoubleDataAttribute(); + if (!device->is_of_type(ClientTrackerDevice::get_class_type())) { + device_cat.error() + << "Inappropriate device type " << device->get_type() + << " created; expected a ClientTrackerDevice.\n"; + return; + } - _tracker_attrib.set_attribute(_ptime_type, _ptime); - _tracker_attrib.set_attribute(_position_type, _position); - _tracker_attrib.set_attribute(_pquat_type, _pquat); + _tracker = DCAST(ClientTrackerDevice, device); - _tracker_attrib.set_attribute(_vtime_type, _vtime); - _tracker_attrib.set_attribute(_velocity_type, _velocity); - _tracker_attrib.set_attribute(_vquat_type, _vquat); - _tracker_attrib.set_attribute(_vquat_dt_type, _vquat_dt); + if (_tracker != (ClientTrackerDevice *)NULL) { + _transform_attrib = new MatrixDataAttribute; + _attrib.set_attribute(_transform_type, _transform_attrib); + } +} - _tracker_attrib.set_attribute(_atime_type, _atime); - _tracker_attrib.set_attribute(_acceleration_type, _acceleration); - _tracker_attrib.set_attribute(_aquat_type, _aquat); - _tracker_attrib.set_attribute(_aquat_dt_type, _aquat_dt); +//////////////////////////////////////////////////////////////////// +// Function: TrackerNode::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +TrackerNode:: +~TrackerNode() { + // When the _tracker pointer destructs, the ClientTrackerDevice + // disconnects itself from the ClientBase, and everything that needs + // to get turned off does. Magic. } //////////////////////////////////////////////////////////////////// @@ -73,32 +66,24 @@ TrackerNode(PT(ClientBase) client, const string &tracker, //////////////////////////////////////////////////////////////////// void TrackerNode:: transmit_data(NodeAttributes &data) { - TrackerData new_data = _client->get_tracker_data(_tracker, _sensor); + if (is_valid()) { + _tracker->poll(); + _tracker->lock(); + _data = _tracker->get_data(); + _tracker->unlock(); - if (device_cat.is_debug()) { - device_cat.debug() << "TrackerNode:transmit_data" << endl; + _data.get_orient().extract_to_matrix(_transform); + _transform.set_row(3, _data.get_pos()); + + _transform_attrib->set_value(_transform); + + if (device_cat.is_debug()) { + device_cat.debug() << "TrackerNode:attributes" << endl; + _attrib.write(device_cat.debug(false), 3); + } } - _ptime->set_value(new_data.ptime); - _position->set_value(new_data.position); - _pquat->set_value(new_data.pquat); - - _vtime->set_value(new_data.vtime); - _velocity->set_value(new_data.velocity); - _vquat->set_value(new_data.vquat); - _vquat_dt->set_value(new_data.vquat_dt); - - _atime->set_value(new_data.atime); - _acceleration->set_value(new_data.acceleration); - _aquat->set_value(new_data.aquat); - _aquat_dt->set_value(new_data.aquat_dt); - - if (device_cat.is_debug()) { - device_cat.debug() << "TrackerNode:attributes" << endl; - _tracker_attrib.write(device_cat.debug(false), 3); - } - - data = _tracker_attrib; + data = _attrib; } //////////////////////////////////////////////////////////////////// @@ -112,45 +97,8 @@ init_type() { register_type(_type_handle, "TrackerNode", DataNode::get_class_type()); - DoubleDataTransition::init_type(); - Vec3DataTransition::init_type(); - Vec4DataTransition::init_type(); - - register_data_transition(_ptime_type, "Position Time", - DoubleDataTransition::get_class_type()); - register_data_transition(_position_type, "Position", - Vec3DataTransition::get_class_type()); - register_data_transition(_pquat_type, "Position Quat", - Vec4DataTransition::get_class_type()); - - register_data_transition(_vtime_type, "Velocity Time", - DoubleDataTransition::get_class_type()); - register_data_transition(_velocity_type, "Velocity", - Vec3DataTransition::get_class_type()); - register_data_transition(_vquat_type, "Velocity Quat", - Vec4DataTransition::get_class_type()); - register_data_transition(_vquat_dt_type, "Velocity Quat dt", - DoubleDataTransition::get_class_type()); - - register_data_transition(_atime_type, "Acceleration Time", - DoubleDataTransition::get_class_type()); - register_data_transition(_acceleration_type, "Acceleration", - Vec3DataTransition::get_class_type()); - register_data_transition(_aquat_type, "Acceleration Quat", - Vec4DataTransition::get_class_type()); - register_data_transition(_aquat_dt_type, "Acceleration Quat dt", - DoubleDataTransition::get_class_type()); + MatrixDataTransition::init_type(); + register_data_transition(_transform_type, "Transform", + MatrixDataTransition::get_class_type()); } - - - - - - - - - - - - diff --git a/panda/src/device/trackerNode.h b/panda/src/device/trackerNode.h index 11922ff111..3f7b0c56ec 100644 --- a/panda/src/device/trackerNode.h +++ b/panda/src/device/trackerNode.h @@ -3,73 +3,59 @@ // //////////////////////////////////////////////////////////////////// -#ifndef _TRACKER_NODE -#define _TRACKER_NODE +#ifndef TRACKERNODE_H +#define TRACKERNODE_H #include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include #include "clientBase.h" +#include "trackerData.h" +#include "clientTrackerDevice.h" + +#include +#include +#include +#include +#include +#include +#include //////////////////////////////////////////////////////////////////// // Class : TrackerNode -// Description : Reads the position, velocity and acceleration -// information from one sensor on a tracker and sends it -// down the DataGraph +// Description : Reads the data associated with a single tracker +// sensor accessed on some ClientBase, and makes the +// data available to user code. Also places the current +// tracker's transform on the data graph. //////////////////////////////////////////////////////////////////// class EXPCL_PANDA TrackerNode : public DataNode { PUBLISHED: - TrackerNode(PT(ClientBase) client, const string &tracker, - int sensor); + TrackerNode(ClientBase *client, const string &device_name); + virtual ~TrackerNode(); + INLINE bool is_valid() const; + + INLINE const LPoint3f &get_pos() const; + INLINE const LOrientationf &get_orient() const; + INLINE const LMatrix4f &get_transform() const; + + +//////////////////////////////////////////////////////////////////// +// From parent class DataNode +//////////////////////////////////////////////////////////////////// public: - virtual void transmit_data(NodeAttributes &data); + virtual void + transmit_data(NodeAttributes &data); -public: - NodeAttributes _tracker_attrib; + NodeAttributes _attrib; + PT(MatrixDataAttribute) _transform_attrib; - PT(DoubleDataAttribute) _ptime; - PT(Vec3DataAttribute) _position; - PT(Vec4DataAttribute) _pquat; - - PT(DoubleDataAttribute) _vtime; - PT(Vec3DataAttribute) _velocity; - PT(Vec4DataAttribute) _vquat; - PT(DoubleDataAttribute) _vquat_dt; + // outputs + static TypeHandle _transform_type; - PT(DoubleDataAttribute) _atime; - PT(Vec3DataAttribute) _acceleration; - PT(Vec4DataAttribute) _aquat; - PT(DoubleDataAttribute) _aquat_dt; - - static TypeHandle _ptime_type; - static TypeHandle _position_type; - static TypeHandle _pquat_type; - - static TypeHandle _vtime_type; - static TypeHandle _velocity_type; - static TypeHandle _vquat_type; - static TypeHandle _vquat_dt_type; - - static TypeHandle _atime_type; - static TypeHandle _acceleration_type; - static TypeHandle _aquat_type; - static TypeHandle _aquat_dt_type; - -protected: - PT(ClientBase) _client; - string _tracker; - int _sensor; +private: + PT(ClientTrackerDevice) _tracker; + TrackerData _data; + LMatrix4f _transform; public: virtual TypeHandle get_type() const { @@ -85,4 +71,6 @@ private: static TypeHandle _type_handle; }; +#include "trackerNode.I" + #endif diff --git a/panda/src/sgraph/geomNode.h b/panda/src/sgraph/geomNode.h index c82fc59a6b..ce72e38c42 100644 --- a/panda/src/sgraph/geomNode.h +++ b/panda/src/sgraph/geomNode.h @@ -37,7 +37,7 @@ public: virtual void xform(const LMatrix4f &mat); PUBLISHED: - void write(ostream &out, int indent_level = 0) const; + virtual void write(ostream &out, int indent_level = 0) const; void write_verbose(ostream &out, int indent_level) const; public: diff --git a/panda/src/tform/mouseWatcher.h b/panda/src/tform/mouseWatcher.h index 4e306b0416..48d9c89a60 100644 --- a/panda/src/tform/mouseWatcher.h +++ b/panda/src/tform/mouseWatcher.h @@ -76,8 +76,8 @@ PUBLISHED: INLINE NodeRelation *get_geometry() const; INLINE void clear_geometry(); - void output(ostream &out) const; - void write(ostream &out, int indent_level = 0) const; + virtual void output(ostream &out) const; + virtual void write(ostream &out, int indent_level = 0) const; private: void set_current_region(MouseWatcherRegion *region); diff --git a/panda/src/vrpn/Sources.pp b/panda/src/vrpn/Sources.pp index 264630cb17..2375d61ac0 100644 --- a/panda/src/vrpn/Sources.pp +++ b/panda/src/vrpn/Sources.pp @@ -11,10 +11,18 @@ #define SOURCES \ config_vrpn.cxx config_vrpn.h vrpnClient.I vrpnClient.cxx \ - vrpnClient.h + vrpnAnalog.I vrpnAnalog.cxx vrpnAnalog.h \ + vrpnAnalogDevice.I vrpnAnalogDevice.cxx vrpnAnalogDevice.h \ + vrpnButton.I vrpnButton.cxx vrpnButton.h \ + vrpnButtonDevice.I vrpnButtonDevice.cxx vrpnButtonDevice.h \ + vrpnClient.h \ + vrpnTracker.I vrpnTracker.cxx vrpnTracker.h \ + vrpnTrackerDevice.I vrpnTrackerDevice.cxx vrpnTrackerDevice.h \ + vrpn_interface.h #define INSTALL_HEADERS \ - config_vrpn.h vrpnClient.I vrpnClient.h + config_vrpn.h \ + vrpnClient.I vrpnClient.h #define IGATESCAN all diff --git a/panda/src/vrpn/config_vrpn.cxx b/panda/src/vrpn/config_vrpn.cxx index 33c38e850f..4431ddfeed 100644 --- a/panda/src/vrpn/config_vrpn.cxx +++ b/panda/src/vrpn/config_vrpn.cxx @@ -4,7 +4,10 @@ //////////////////////////////////////////////////////////////////// #include "config_vrpn.h" +#include "vrpnAnalogDevice.h" +#include "vrpnButtonDevice.h" #include "vrpnClient.h" +#include "vrpnTrackerDevice.h" #include @@ -13,5 +16,8 @@ NotifyCategoryDef(vrpn, ""); ConfigureFn(config_vrpn) { + VrpnAnalogDevice::init_type(); + VrpnButtonDevice::init_type(); VrpnClient::init_type(); + VrpnTrackerDevice::init_type(); } diff --git a/panda/src/vrpn/vrpnAnalog.I b/panda/src/vrpn/vrpnAnalog.I new file mode 100644 index 0000000000..9458d6d73e --- /dev/null +++ b/panda/src/vrpn/vrpnAnalog.I @@ -0,0 +1,38 @@ +// Filename: vrpnAnalog.I +// Created by: drose (26Jan01) +// +//////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////// +// Function: VrpnAnalog::get_analog_name +// Access: Public +// Description: Returns the name of the analog device that was used +// to create this VrpnAnalog. +//////////////////////////////////////////////////////////////////// +INLINE const string &VrpnAnalog:: +get_analog_name() const { + return _analog_name; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnAnalog::is_empty +// Access: Public +// Description: Returns true if no VrpnAnalogDevices reference this +// VrpnAnalog, or false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool VrpnAnalog:: +is_empty() const { + return _devices.empty(); +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnAnalog::poll +// Access: Public +// Description: Polls the connected device. Normally you should not +// call this directly; this will be called by the +// VrpnClient. +//////////////////////////////////////////////////////////////////// +INLINE void VrpnAnalog:: +poll() { + _analog->mainloop(); +} diff --git a/panda/src/vrpn/vrpnAnalog.cxx b/panda/src/vrpn/vrpnAnalog.cxx new file mode 100644 index 0000000000..2f001f533e --- /dev/null +++ b/panda/src/vrpn/vrpnAnalog.cxx @@ -0,0 +1,121 @@ +// Filename: vrpnAnalog.cxx +// Created by: drose (26Jan01) +// +//////////////////////////////////////////////////////////////////// + +#include "vrpnAnalog.h" +#include "vrpnAnalogDevice.h" +#include "vrpnClient.h" +#include "config_vrpn.h" + +#include + +#include + +//////////////////////////////////////////////////////////////////// +// Function: VrpnAnalog::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +VrpnAnalog:: +VrpnAnalog(const string &analog_name, vrpn_Connection *connection) : + _analog_name(analog_name) +{ + _analog = new vrpn_Analog_Remote(_analog_name.c_str(), connection); + + _analog->register_change_handler((void*)this, &vrpn_analog_callback); +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnAnalog::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +VrpnAnalog:: +~VrpnAnalog() { + delete _analog; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnAnalog::mark +// Access: Public +// Description: Adds the indicated VrpnAnalogDevice to the list of +// devices that are sharing this VrpnAnalog. +//////////////////////////////////////////////////////////////////// +void VrpnAnalog:: +mark(VrpnAnalogDevice *device) { + if (vrpn_cat.is_debug()) { + vrpn_cat.debug() << *this << " marking " << *device << "\n"; + } + _devices.push_back(device); +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnAnalog::unmark +// Access: Public +// Description: Removes the indicated VrpnAnalogDevice from the list +// of devices that are sharing this VrpnAnalog. +//////////////////////////////////////////////////////////////////// +void VrpnAnalog:: +unmark(VrpnAnalogDevice *device) { + if (vrpn_cat.is_debug()) { + vrpn_cat.debug() << *this << " unmarking " << *device << "\n"; + } + + Devices::iterator di = + find(_devices.begin(), _devices.end(), device); + + if (di != _devices.end()) { + _devices.erase(di); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnAnalog::output +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void VrpnAnalog:: +output(ostream &out) const { + out << _analog_name; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnAnalog::write +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void VrpnAnalog:: +write(ostream &out, int indent_level) const { + indent(out, indent_level) + << get_analog_name() << " (" + << _devices.size() << " devices)\n"; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnAnalog::vrpn_analog_callback +// Access: Private, Static +// Description: Receives the analog event data from the VRPN +// code and sends it to any interested +// VrpnAnalogDevices. +//////////////////////////////////////////////////////////////////// +void VrpnAnalog:: +vrpn_analog_callback(void *userdata, const vrpn_ANALOGCB info) { + VrpnAnalog *self = (VrpnAnalog *)userdata; + + Devices::iterator di; + for (di = self->_devices.begin(); di != self->_devices.end(); ++di) { + VrpnAnalogDevice *device = (*di); + device->lock(); + for (int i = 0; i < info.num_channel; i++) { + if (vrpn_cat.is_debug()) { + if (device->get_control_state(i) != info.channel[i]) { + vrpn_cat.debug() + << *self << " got analog " << i << " = " << info.channel[i] << "\n"; + } + } + device->set_control_state(i, info.channel[i]); + } + device->unlock(); + } +} diff --git a/panda/src/vrpn/vrpnAnalog.h b/panda/src/vrpn/vrpnAnalog.h new file mode 100644 index 0000000000..8f9251c434 --- /dev/null +++ b/panda/src/vrpn/vrpnAnalog.h @@ -0,0 +1,68 @@ +// Filename: vrpnAnalog.h +// Created by: drose (26Jan01) +// +//////////////////////////////////////////////////////////////////// + +#ifndef VRPNANALOG_H +#define VRPNANALOG_H + +#include + +#include "vrpn_interface.h" + +#include + +class VrpnAnalogDevice; + +//////////////////////////////////////////////////////////////////// +// Class : VrpnAnalog +// Description : This is the actual interface to a particular VRPN +// analog device, and all of its numbered controls. A +// pointer to this object is stored in the VrpnClient +// class for each differently-named VRPN analog device +// we connect to. +// +// The VRPN callbacks go here, which in turn get +// vectored out to any VrpnAnalogDevice objects that +// register with this. When the last VrpnAnalogDevice +// object unregisters, the VrpnAnalog will be deleted +// by the VrpnClient. +// +// This class does not need to be exported from the DLL. +//////////////////////////////////////////////////////////////////// +class VrpnAnalog { +public: + VrpnAnalog(const string &analog_name, vrpn_Connection *connection); + ~VrpnAnalog(); + + INLINE const string &get_analog_name() const; + INLINE bool is_empty() const; + + void mark(VrpnAnalogDevice *device); + void unmark(VrpnAnalogDevice *device); + + INLINE void poll(); + + void output(ostream &out) const; + void write(ostream &out, int indent_level = 0) const; + +private: + static void + vrpn_analog_callback(void *userdata, const vrpn_ANALOGCB info); + +private: + string _analog_name; + vrpn_Analog_Remote *_analog; + + typedef vector Devices; + Devices _devices; +}; + +INLINE ostream &operator << (ostream &out, const VrpnAnalog &analog) { + analog.output(out); + return out; +} + +#include "vrpnAnalog.I" + +#endif diff --git a/panda/src/vrpn/vrpnAnalogDevice.I b/panda/src/vrpn/vrpnAnalogDevice.I new file mode 100644 index 0000000000..a4e2814f43 --- /dev/null +++ b/panda/src/vrpn/vrpnAnalogDevice.I @@ -0,0 +1,17 @@ +// Filename: vrpnAnalogDevice.I +// Created by: drose (26Jan01) +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: VrpnAnalogDevice::get_vrpn_analog +// Access: Public +// Description: Returns a pointer to the particular VrpnAnalog this +// device gets its data from. This pointer may be +// shared with other VrpnAnalogDevice objects. +//////////////////////////////////////////////////////////////////// +INLINE VrpnAnalog *VrpnAnalogDevice:: +get_vrpn_analog() const { + return _vrpn_analog; +} diff --git a/panda/src/vrpn/vrpnAnalogDevice.cxx b/panda/src/vrpn/vrpnAnalogDevice.cxx new file mode 100644 index 0000000000..85d3fb426d --- /dev/null +++ b/panda/src/vrpn/vrpnAnalogDevice.cxx @@ -0,0 +1,32 @@ +// Filename: vrpnAnalogDevice.cxx +// Created by: drose (26Jan01) +// +//////////////////////////////////////////////////////////////////// + +#include "vrpnAnalogDevice.h" +#include "vrpnClient.h" + +TypeHandle VrpnAnalogDevice::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: VrpnAnalogDevice::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +VrpnAnalogDevice:: +VrpnAnalogDevice(VrpnClient *client, const string &device_name, + VrpnAnalog *vrpn_analog) : + ClientAnalogDevice(client, device_name), + _vrpn_analog(vrpn_analog) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnAnalogDevice::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +VrpnAnalogDevice:: +~VrpnAnalogDevice() { + disconnect(); +} diff --git a/panda/src/vrpn/vrpnAnalogDevice.h b/panda/src/vrpn/vrpnAnalogDevice.h new file mode 100644 index 0000000000..f2608509b9 --- /dev/null +++ b/panda/src/vrpn/vrpnAnalogDevice.h @@ -0,0 +1,57 @@ +// Filename: vrpnAnalogDevice.h +// Created by: drose (26Jan01) +// +//////////////////////////////////////////////////////////////////// + +#ifndef VRPNANALOGDEVICE_H +#define VRPNANALOGDEVICE_H + +#include + +#include + +class VrpnClient; +class VrpnAnalog; + +//////////////////////////////////////////////////////////////////// +// Class : VrpnAnalogDevice +// Description : The Panda interface to a VRPN analog device. This +// object will be returned by VrpnClient::make_device(), +// for attaching to a AnalogNode. +// +// This class does not need to be exported from the DLL. +//////////////////////////////////////////////////////////////////// +class VrpnAnalogDevice : public ClientAnalogDevice { +public: + VrpnAnalogDevice(VrpnClient *client, const string &device_name, + VrpnAnalog *vrpn_analog); + virtual ~VrpnAnalogDevice(); + + INLINE VrpnAnalog *get_vrpn_analog() const; + +private: + VrpnAnalog *_vrpn_analog; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + ClientAnalogDevice::init_type(); + register_type(_type_handle, "VrpnAnalogDevice", + ClientAnalogDevice::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; + + friend class VrpnAnalog; +}; + +#include "vrpnAnalogDevice.I" + +#endif diff --git a/panda/src/vrpn/vrpnButton.I b/panda/src/vrpn/vrpnButton.I new file mode 100644 index 0000000000..8ca8e50821 --- /dev/null +++ b/panda/src/vrpn/vrpnButton.I @@ -0,0 +1,38 @@ +// Filename: vrpnButton.I +// Created by: drose (26Jan01) +// +//////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////// +// Function: VrpnButton::get_button_name +// Access: Public +// Description: Returns the name of the button device that was used +// to create this VrpnButton. +//////////////////////////////////////////////////////////////////// +INLINE const string &VrpnButton:: +get_button_name() const { + return _button_name; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnButton::is_empty +// Access: Public +// Description: Returns true if no VrpnButtonDevices reference this +// VrpnButton, or false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool VrpnButton:: +is_empty() const { + return _devices.empty(); +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnButton::poll +// Access: Public +// Description: Polls the connected device. Normally you should not +// call this directly; this will be called by the +// VrpnClient. +//////////////////////////////////////////////////////////////////// +INLINE void VrpnButton:: +poll() { + _button->mainloop(); +} diff --git a/panda/src/vrpn/vrpnButton.cxx b/panda/src/vrpn/vrpnButton.cxx new file mode 100644 index 0000000000..3c9b39a04d --- /dev/null +++ b/panda/src/vrpn/vrpnButton.cxx @@ -0,0 +1,117 @@ +// Filename: vrpnButton.cxx +// Created by: drose (26Jan01) +// +//////////////////////////////////////////////////////////////////// + +#include "vrpnButton.h" +#include "vrpnButtonDevice.h" +#include "vrpnClient.h" +#include "config_vrpn.h" + +#include + +#include + +//////////////////////////////////////////////////////////////////// +// Function: VrpnButton::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +VrpnButton:: +VrpnButton(const string &button_name, vrpn_Connection *connection) : + _button_name(button_name) +{ + _button = new vrpn_Button_Remote(_button_name.c_str(), connection); + + _button->register_change_handler((void*)this, &vrpn_button_callback); +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnButton::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +VrpnButton:: +~VrpnButton() { + delete _button; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnButton::mark +// Access: Public +// Description: Adds the indicated VrpnButtonDevice to the list of +// devices that are sharing this VrpnButton. +//////////////////////////////////////////////////////////////////// +void VrpnButton:: +mark(VrpnButtonDevice *device) { + if (vrpn_cat.is_debug()) { + vrpn_cat.debug() << *this << " marking " << *device << "\n"; + } + _devices.push_back(device); +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnButton::unmark +// Access: Public +// Description: Removes the indicated VrpnButtonDevice from the list +// of devices that are sharing this VrpnButton. +//////////////////////////////////////////////////////////////////// +void VrpnButton:: +unmark(VrpnButtonDevice *device) { + if (vrpn_cat.is_debug()) { + vrpn_cat.debug() << *this << " unmarking " << *device << "\n"; + } + + Devices::iterator di = + find(_devices.begin(), _devices.end(), device); + + if (di != _devices.end()) { + _devices.erase(di); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnButton::output +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void VrpnButton:: +output(ostream &out) const { + out << _button_name; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnButton::write +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void VrpnButton:: +write(ostream &out, int indent_level) const { + indent(out, indent_level) + << get_button_name() << " (" + << _devices.size() << " devices)\n"; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnButton::vrpn_button_callback +// Access: Private, Static +// Description: Receives the button event data from the VRPN +// code and sends it to any interested +// VrpnButtonDevices. +//////////////////////////////////////////////////////////////////// +void VrpnButton:: +vrpn_button_callback(void *userdata, const vrpn_BUTTONCB info) { + VrpnButton *self = (VrpnButton *)userdata; + if (vrpn_cat.is_debug()) { + vrpn_cat.debug() + << *self << " got button " << info.button << " = " << info.state << "\n"; + } + + Devices::iterator di; + for (di = self->_devices.begin(); di != self->_devices.end(); ++di) { + VrpnButtonDevice *device = (*di); + device->lock(); + device->set_button_state(info.button, info.state != 0); + device->unlock(); + } +} diff --git a/panda/src/vrpn/vrpnButton.h b/panda/src/vrpn/vrpnButton.h new file mode 100644 index 0000000000..3ebb663224 --- /dev/null +++ b/panda/src/vrpn/vrpnButton.h @@ -0,0 +1,68 @@ +// Filename: vrpnButton.h +// Created by: drose (26Jan01) +// +//////////////////////////////////////////////////////////////////// + +#ifndef VRPNBUTTON_H +#define VRPNBUTTON_H + +#include + +#include "vrpn_interface.h" + +#include + +class VrpnButtonDevice; + +//////////////////////////////////////////////////////////////////// +// Class : VrpnButton +// Description : This is the actual interface to a particular VRPN +// button device, and all of its numbered buttons. A +// pointer to this object is stored in the VrpnClient +// class for each differently-named VRPN button device +// we connect to. +// +// The VRPN callbacks go here, which in turn get +// vectored out to any VrpnButtonDevice objects that +// register with this. When the last VrpnButtonDevice +// object unregisters, the VrpnButton will be deleted +// by the VrpnClient. +// +// This class does not need to be exported from the DLL. +//////////////////////////////////////////////////////////////////// +class VrpnButton { +public: + VrpnButton(const string &button_name, vrpn_Connection *connection); + ~VrpnButton(); + + INLINE const string &get_button_name() const; + INLINE bool is_empty() const; + + void mark(VrpnButtonDevice *device); + void unmark(VrpnButtonDevice *device); + + INLINE void poll(); + + void output(ostream &out) const; + void write(ostream &out, int indent_level = 0) const; + +private: + static void + vrpn_button_callback(void *userdata, const vrpn_BUTTONCB info); + +private: + string _button_name; + vrpn_Button_Remote *_button; + + typedef vector Devices; + Devices _devices; +}; + +INLINE ostream &operator << (ostream &out, const VrpnButton &button) { + button.output(out); + return out; +} + +#include "vrpnButton.I" + +#endif diff --git a/panda/src/vrpn/vrpnButtonDevice.I b/panda/src/vrpn/vrpnButtonDevice.I new file mode 100644 index 0000000000..ff88455ac8 --- /dev/null +++ b/panda/src/vrpn/vrpnButtonDevice.I @@ -0,0 +1,17 @@ +// Filename: vrpnButtonDevice.I +// Created by: drose (26Jan01) +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: VrpnButtonDevice::get_vrpn_button +// Access: Public +// Description: Returns a pointer to the particular VrpnButton this +// device gets its data from. This pointer may be +// shared with other VrpnButtonDevice objects. +//////////////////////////////////////////////////////////////////// +INLINE VrpnButton *VrpnButtonDevice:: +get_vrpn_button() const { + return _vrpn_button; +} diff --git a/panda/src/vrpn/vrpnButtonDevice.cxx b/panda/src/vrpn/vrpnButtonDevice.cxx new file mode 100644 index 0000000000..3a1f09a88c --- /dev/null +++ b/panda/src/vrpn/vrpnButtonDevice.cxx @@ -0,0 +1,32 @@ +// Filename: vrpnButtonDevice.cxx +// Created by: drose (26Jan01) +// +//////////////////////////////////////////////////////////////////// + +#include "vrpnButtonDevice.h" +#include "vrpnClient.h" + +TypeHandle VrpnButtonDevice::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: VrpnButtonDevice::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +VrpnButtonDevice:: +VrpnButtonDevice(VrpnClient *client, const string &device_name, + VrpnButton *vrpn_button) : + ClientButtonDevice(client, device_name), + _vrpn_button(vrpn_button) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnButtonDevice::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +VrpnButtonDevice:: +~VrpnButtonDevice() { + disconnect(); +} diff --git a/panda/src/vrpn/vrpnButtonDevice.h b/panda/src/vrpn/vrpnButtonDevice.h new file mode 100644 index 0000000000..e5d3b608e4 --- /dev/null +++ b/panda/src/vrpn/vrpnButtonDevice.h @@ -0,0 +1,57 @@ +// Filename: vrpnButtonDevice.h +// Created by: drose (26Jan01) +// +//////////////////////////////////////////////////////////////////// + +#ifndef VRPNBUTTONDEVICE_H +#define VRPNBUTTONDEVICE_H + +#include + +#include + +class VrpnClient; +class VrpnButton; + +//////////////////////////////////////////////////////////////////// +// Class : VrpnButtonDevice +// Description : The Panda interface to a VRPN button. This object +// will be returned by VrpnClient::make_device(), for +// attaching to a ButtonNode. +// +// This class does not need to be exported from the DLL. +//////////////////////////////////////////////////////////////////// +class VrpnButtonDevice : public ClientButtonDevice { +public: + VrpnButtonDevice(VrpnClient *client, const string &device_name, + VrpnButton *vrpn_button); + virtual ~VrpnButtonDevice(); + + INLINE VrpnButton *get_vrpn_button() const; + +private: + VrpnButton *_vrpn_button; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + ClientButtonDevice::init_type(); + register_type(_type_handle, "VrpnButtonDevice", + ClientButtonDevice::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; + + friend class VrpnButton; +}; + +#include "vrpnButtonDevice.I" + +#endif diff --git a/panda/src/vrpn/vrpnClient.I b/panda/src/vrpn/vrpnClient.I index 620e084eda..9e80a3bfde 100644 --- a/panda/src/vrpn/vrpnClient.I +++ b/panda/src/vrpn/vrpnClient.I @@ -5,6 +5,57 @@ +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::get_server_name +// Access: Public +// Description: Returns the name of the server as passed to the +// VrpnClient constructor. +//////////////////////////////////////////////////////////////////// +INLINE const string &VrpnClient:: +get_server_name() const { + return _server_name; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::is_valid +// Access: Public +// Description: Returns true if everything seems to be kosher with +// the server (even if there is no connection), or false +// otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool VrpnClient:: +is_valid() const { + return _connection->doing_okay(); +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::is_connected +// Access: Public +// Description: Returns true if the connection is established +// succesfully, false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool VrpnClient:: +is_connected() const { + return _connection->connected(); +} + + +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::convert_to_secs +// Access: Public, Static +// Description: Little inline function to convert a struct timeval +// to only seconds +//////////////////////////////////////////////////////////////////// +INLINE double VrpnClient:: +convert_to_secs(struct timeval msg_time) { + return (double)(msg_time.tv_sec) + (double)msg_time.tv_usec * 0.000001; +} + + + + +#if 0 + //////////////////////////////////////////////////////////////////// // Function: VrpnClient::constructor // Access: Public @@ -107,12 +158,4 @@ dial(const string &dial, const vrpn_DIALCB info) { push_dial(dial, dtime, info.dial, info.change); } -//////////////////////////////////////////////////////////////////// -// Function: convert_to_secs -// Access: Public -// Description: Little inline function to convert a struct timeval -// to only seconds -//////////////////////////////////////////////////////////////////// -INLINE double convert_to_secs(struct timeval msg_time) { - return (double)(msg_time.tv_sec) + (double)msg_time.tv_usec * 0.000001; -} +#endif diff --git a/panda/src/vrpn/vrpnClient.cxx b/panda/src/vrpn/vrpnClient.cxx index 84d5a56751..789a1877ef 100644 --- a/panda/src/vrpn/vrpnClient.cxx +++ b/panda/src/vrpn/vrpnClient.cxx @@ -4,9 +4,548 @@ //////////////////////////////////////////////////////////////////// #include "vrpnClient.h" +#include "vrpnTracker.h" +#include "vrpnTrackerDevice.h" +#include "vrpnButton.h" +#include "vrpnButtonDevice.h" +#include "vrpnAnalog.h" +#include "vrpnAnalogDevice.h" +#include "config_vrpn.h" + +#include +#include TypeHandle VrpnClient::_type_handle; +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +VrpnClient:: +VrpnClient(const string &server_name) : + _server_name(server_name) +{ + if (vrpn_cat.is_debug()) { + vrpn_cat.debug() + << "Attempting to connect to VRPN server " << _server_name + << "\n"; + } + _connection = vrpn_get_connection_by_name(_server_name.c_str()); + nassertv(_connection != (vrpn_Connection *)NULL); + + if (!is_valid()) { + vrpn_cat.warning() + << "Unable to establish connection to VRPN server " << _server_name + << "\n"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +VrpnClient:: +~VrpnClient() { + delete _connection; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::write +// Access: Public +// Description: Writes a list of the active devices that the +// VrpnClient is currently polling each frame. +//////////////////////////////////////////////////////////////////// +void VrpnClient:: +write(ostream &out, int indent_level) const { + indent(out, indent_level) + << "VrpnClient, server " << _server_name << "\n"; + + if (!is_valid()) { + indent(out, indent_level + 2) + << "(error)\n"; + } else if (!is_connected()) { + indent(out, indent_level + 2) + << "(no connection)\n"; + } + + if (!_trackers.empty()) { + indent(out, indent_level + 2) + << _trackers.size() << " trackers:\n"; + Trackers::const_iterator ti; + for (ti = _trackers.begin(); ti != _trackers.end(); ++ti) { + VrpnTracker *vrpn_tracker = (*ti).second; + vrpn_tracker->write(out, indent_level + 4); + } + } + + if (!_buttons.empty()) { + indent(out, indent_level + 2) + << _buttons.size() << " buttons:\n"; + Buttons::const_iterator bi; + for (bi = _buttons.begin(); bi != _buttons.end(); ++bi) { + VrpnButton *vrpn_button = (*bi).second; + vrpn_button->write(out, indent_level + 4); + } + } + + if (!_analogs.empty()) { + indent(out, indent_level + 2) + << _analogs.size() << " analogs:\n"; + Analogs::const_iterator ai; + for (ai = _analogs.begin(); ai != _analogs.end(); ++ai) { + VrpnAnalog *vrpn_analog = (*ai).second; + vrpn_analog->write(out, indent_level + 4); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::make_device +// Access: Protected, Virtual +// Description: Creates and returns a new ClientDevice of the +// appropriate type, according to the requested +// device_type and device_name. Returns NULL if a +// matching device cannot be found. +// +// This is guaranteed not to be called twice for a given +// device_type/device_name combination (unless +// disconnect_device() has already been called for the +// same device_type/device_name). +//////////////////////////////////////////////////////////////////// +PT(ClientDevice) VrpnClient:: +make_device(TypeHandle device_type, const string &device_name) { + if (device_type == ClientTrackerDevice::get_class_type()) { + return make_tracker_device(device_name); + + } else if (device_type == ClientButtonDevice::get_class_type()) { + return make_button_device(device_name); + + } else if (device_type == ClientAnalogDevice::get_class_type()) { + return make_analog_device(device_name); + + } else { + return NULL; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::disconnect_device +// Access: Protected, Virtual +// Description: Removes the device, which is presumably about to +// destruct, from the list of connected devices, and +// frees any data required to support it. This device +// will no longer receive automatic updates with each +// poll. +// +// The return value is true if the device was +// disconnected, or false if it was unknown (e.g. it was +// disconnected previously). +//////////////////////////////////////////////////////////////////// +bool VrpnClient:: +disconnect_device(TypeHandle device_type, const string &device_name, + ClientDevice *device) { + if (vrpn_cat.is_debug()) { + vrpn_cat.debug() + << "Disconnecting device " << *device << "\n"; + } + + if (ClientBase::disconnect_device(device_type, device_name, device)) { + if (device->is_of_type(VrpnTrackerDevice::get_class_type())) { + disconnect_tracker_device(DCAST(VrpnTrackerDevice, device)); + + } else if (device->is_of_type(VrpnButtonDevice::get_class_type())) { + disconnect_button_device(DCAST(VrpnButtonDevice, device)); + + } else if (device->is_of_type(VrpnAnalogDevice::get_class_type())) { + disconnect_analog_device(DCAST(VrpnAnalogDevice, device)); + + } + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::do_poll +// Access: Protected, Virtual +// Description: Implements the polling and updating of connected +// devices, if the ClientBase requires this. This may +// be called in a sub-thread if +// fork_asynchronous_thread() was called; otherwise, it +// will be called once per frame. +//////////////////////////////////////////////////////////////////// +void VrpnClient:: +do_poll() { + ClientBase::do_poll(); + + if (vrpn_cat.is_spam()) { + vrpn_cat.spam() + << "VrpnClient " << _server_name << " polling " + << _trackers.size() + _buttons.size() + _analogs.size() + << " devices.\n"; + } + + Trackers::iterator ti; + for (ti = _trackers.begin(); ti != _trackers.end(); ++ti) { + VrpnTracker *vrpn_tracker = (*ti).second; + vrpn_tracker->poll(); + } + + Buttons::iterator bi; + for (bi = _buttons.begin(); bi != _buttons.end(); ++bi) { + VrpnButton *vrpn_button = (*bi).second; + vrpn_button->poll(); + } + + Analogs::iterator ai; + for (ai = _analogs.begin(); ai != _analogs.end(); ++ai) { + VrpnAnalog *vrpn_analog = (*ai).second; + vrpn_analog->poll(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::make_tracker_device +// Access: Private +// Description: Creates a new tracker device. The device_name is +// parsed for sensor and data_type information. +// +// The device_name may be one of the following: +// +// tracker_name +// tracker_name:N +// tracker_name:N[pva] +// +// Where N is an integer sensor number, and [pva] is one +// of the lowercase letters p, v, or a. +// +// In the first form, the device connects to the +// indicated tracker, and reports position information +// on sensor number 0. +// +// In the second form, the device connects to the +// indicated tracker, and reports position information +// on the indicated sensor number. +// +// In the third form, the device connects to the +// indicated tracker, and reports either position, +// velocity, or acceleration information on the +// indicated sensor number. +//////////////////////////////////////////////////////////////////// +PT(ClientDevice) VrpnClient:: +make_tracker_device(const string &device_name) { + if (vrpn_cat.is_debug()) { + vrpn_cat.debug() + << "Making tracker device for " << device_name << "\n"; + } + + string tracker_name = device_name; + int sensor = 0; + VrpnTrackerDevice::DataType data_type = VrpnTrackerDevice::DT_position; + + size_t colon = device_name.rfind(':'); + if (colon != string::npos && colon + 1 < device_name.length()) { + size_t begin = colon + 1; + size_t end = device_name.length(); + VrpnTrackerDevice::DataType maybe_data_type = data_type; + + switch (device_name[end - 1]) { + case 'p': + maybe_data_type = VrpnTrackerDevice::DT_position; + end--; + break; + + case 'v': + maybe_data_type = VrpnTrackerDevice::DT_velocity; + end--; + break; + + case 'a': + maybe_data_type = VrpnTrackerDevice::DT_acceleration; + end--; + break; + } + int maybe_sensor; + if (string_to_int(device_name.substr(begin, end - begin), maybe_sensor)) { + // It seems to be a legitimate integer! + sensor = maybe_sensor; + data_type = maybe_data_type; + tracker_name = device_name.substr(0, colon); + } + } + + VrpnTracker *tracker = get_tracker(tracker_name); + + VrpnTrackerDevice *device = + new VrpnTrackerDevice(this, device_name, sensor, data_type, tracker); + + if (vrpn_cat.is_debug()) { + vrpn_cat.debug() + << "Creating " << *device << "\n"; + } + + tracker->mark(device); + return device; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::make_button_device +// Access: Private +// Description: Creates a new button device. The device_name is sent +// verbatim to the VRPN library. +//////////////////////////////////////////////////////////////////// +PT(ClientDevice) VrpnClient:: +make_button_device(const string &device_name) { + if (vrpn_cat.is_debug()) { + vrpn_cat.debug() + << "Making button device for " << device_name << "\n"; + } + + VrpnButton *button = get_button(device_name); + + VrpnButtonDevice *device = + new VrpnButtonDevice(this, device_name, button); + + if (vrpn_cat.is_debug()) { + vrpn_cat.debug() + << "Creating " << *device << "\n"; + } + + button->mark(device); + return device; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::make_analog_device +// Access: Private +// Description: Creates a new analog device. The device_name is sent +// verbatim to the VRPN library. +//////////////////////////////////////////////////////////////////// +PT(ClientDevice) VrpnClient:: +make_analog_device(const string &device_name) { + if (vrpn_cat.is_debug()) { + vrpn_cat.debug() + << "Making analog device for " << device_name << "\n"; + } + + VrpnAnalog *analog = get_analog(device_name); + + VrpnAnalogDevice *device = + new VrpnAnalogDevice(this, device_name, analog); + + if (vrpn_cat.is_debug()) { + vrpn_cat.debug() + << "Creating " << *device << "\n"; + } + + analog->mark(device); + return device; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::disconnect_tracker_device +// Access: Private +// Description: Removes the tracker device from the list of things to +// be updated. +//////////////////////////////////////////////////////////////////// +void VrpnClient:: +disconnect_tracker_device(VrpnTrackerDevice *device) { + VrpnTracker *vrpn_tracker = device->get_vrpn_tracker(); + vrpn_tracker->unmark(device); + if (vrpn_tracker->is_empty()) { + free_tracker(vrpn_tracker); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::disconnect_button_device +// Access: Private +// Description: Removes the button device from the list of things to +// be updated. +//////////////////////////////////////////////////////////////////// +void VrpnClient:: +disconnect_button_device(VrpnButtonDevice *device) { + VrpnButton *vrpn_button = device->get_vrpn_button(); + vrpn_button->unmark(device); + if (vrpn_button->is_empty()) { + free_button(vrpn_button); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::disconnect_analog_device +// Access: Private +// Description: Removes the analog device from the list of things to +// be updated. +//////////////////////////////////////////////////////////////////// +void VrpnClient:: +disconnect_analog_device(VrpnAnalogDevice *device) { + VrpnAnalog *vrpn_analog = device->get_vrpn_analog(); + vrpn_analog->unmark(device); + if (vrpn_analog->is_empty()) { + free_analog(vrpn_analog); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::get_tracker +// Access: Private +// Description: Finds a VrpnTracker of the indicated name, and +// returns it if one already exists, or creates a new +// one if it does not. +//////////////////////////////////////////////////////////////////// +VrpnTracker *VrpnClient:: +get_tracker(const string &tracker_name) { + Trackers::iterator ti; + ti = _trackers.find(tracker_name); + + if (ti != _trackers.end()) { + return (*ti).second; + } + + VrpnTracker *vrpn_tracker = new VrpnTracker(tracker_name, _connection); + _trackers.insert(Trackers::value_type(tracker_name, vrpn_tracker)); + + if (vrpn_cat.is_debug()) { + vrpn_cat.debug() + << "Creating tracker " << *vrpn_tracker << "\n"; + } + + return vrpn_tracker; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::free_tracker +// Access: Private +// Description: Removes and deletes the indicated VrpnTracker, which +// is no longer referenced by any VrpnTrackerDevices. +//////////////////////////////////////////////////////////////////// +void VrpnClient:: +free_tracker(VrpnTracker *vrpn_tracker) { + nassertv(vrpn_tracker->is_empty()); + + if (vrpn_cat.is_debug()) { + vrpn_cat.debug() + << "Deleting tracker " << *vrpn_tracker << "\n"; + } + + Trackers::iterator ti; + ti = _trackers.find(vrpn_tracker->get_tracker_name()); + nassertv(ti != _trackers.end()); + nassertv((*ti).second == vrpn_tracker); + + _trackers.erase(ti); + delete vrpn_tracker; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::get_button +// Access: Private +// Description: Finds a VrpnButton of the indicated name, and +// returns it if one already exists, or creates a new +// one if it does not. +//////////////////////////////////////////////////////////////////// +VrpnButton *VrpnClient:: +get_button(const string &button_name) { + Buttons::iterator bi; + bi = _buttons.find(button_name); + + if (bi != _buttons.end()) { + return (*bi).second; + } + + VrpnButton *vrpn_button = new VrpnButton(button_name, _connection); + _buttons.insert(Buttons::value_type(button_name, vrpn_button)); + + if (vrpn_cat.is_debug()) { + vrpn_cat.debug() + << "Creating button " << *vrpn_button << "\n"; + } + + return vrpn_button; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::free_button +// Access: Private +// Description: Removes and deletes the indicated VrpnButton, which +// is no longer referenced by any VrpnButtonDevices. +//////////////////////////////////////////////////////////////////// +void VrpnClient:: +free_button(VrpnButton *vrpn_button) { + nassertv(vrpn_button->is_empty()); + + if (vrpn_cat.is_debug()) { + vrpn_cat.debug() + << "Deleting button " << *vrpn_button << "\n"; + } + + Buttons::iterator bi; + bi = _buttons.find(vrpn_button->get_button_name()); + nassertv(bi != _buttons.end()); + nassertv((*bi).second == vrpn_button); + + _buttons.erase(bi); + delete vrpn_button; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::get_analog +// Access: Private +// Description: Finds a VrpnAnalog of the indicated name, and +// returns it if one already exists, or creates a new +// one if it does not. +//////////////////////////////////////////////////////////////////// +VrpnAnalog *VrpnClient:: +get_analog(const string &analog_name) { + Analogs::iterator ai; + ai = _analogs.find(analog_name); + + if (ai != _analogs.end()) { + return (*ai).second; + } + + VrpnAnalog *vrpn_analog = new VrpnAnalog(analog_name, _connection); + _analogs.insert(Analogs::value_type(analog_name, vrpn_analog)); + + if (vrpn_cat.is_debug()) { + vrpn_cat.debug() + << "Creating analog " << *vrpn_analog << "\n"; + } + + return vrpn_analog; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnClient::free_analog +// Access: Private +// Description: Removes and deletes the indicated VrpnAnalog, which +// is no longer referenced by any VrpnAnalogDevices. +//////////////////////////////////////////////////////////////////// +void VrpnClient:: +free_analog(VrpnAnalog *vrpn_analog) { + nassertv(vrpn_analog->is_empty()); + + if (vrpn_cat.is_debug()) { + vrpn_cat.debug() + << "Deleting analog " << *vrpn_analog << "\n"; + } + + Analogs::iterator ai; + ai = _analogs.find(vrpn_analog->get_analog_name()); + nassertv(ai != _analogs.end()); + nassertv((*ai).second == vrpn_analog); + + _analogs.erase(ai); + delete vrpn_analog; +} + + +#if 0 + #include #include @@ -261,3 +800,5 @@ st_dial(void *userdata, const vrpn_DIALCB info) { VrpnClientInfo *data = (VrpnClientInfo *)userdata; ((VrpnClient *)data->self)->dial(data->device_name, info); } + +#endif diff --git a/panda/src/vrpn/vrpnClient.h b/panda/src/vrpn/vrpnClient.h index 389f122dc5..b13fc75270 100644 --- a/panda/src/vrpn/vrpnClient.h +++ b/panda/src/vrpn/vrpnClient.h @@ -3,110 +3,99 @@ // //////////////////////////////////////////////////////////////////// -#ifndef VRPN_CLIENT -#define VRPN_CLIENT +#ifndef VRPNCLIENT_H +#define VRPNCLIENT_H #include #include -#ifdef CPPPARSER - // For correct interrogate parsing of UNC's vrpn library. - #ifdef WIN32_VC - #define _WIN32 - #define SOCKET int - #else - #define linux - typedef struct timeval timeval; - #endif -#endif +#include "vrpn_interface.h" -#include -#include -#include -#include -#include +class VrpnTracker; +class VrpnTrackerDevice; +class VrpnButton; +class VrpnButtonDevice; +class VrpnAnalog; +class VrpnAnalogDevice; +//////////////////////////////////////////////////////////////////// +// Class : VrpnClient +// Description : A specific ClientBase that connects to a VRPN server +// and records information on the connected VRPN +// devices. +//////////////////////////////////////////////////////////////////// class EXPCL_PANDA VrpnClient : public ClientBase { PUBLISHED: - INLINE VrpnClient(const string &server); + VrpnClient(const string &server_name); + ~VrpnClient(); + + INLINE const string &get_server_name() const; + INLINE bool is_valid() const; + INLINE bool is_connected() const; + + void write(ostream &out, int indent_level = 0) const; public: - //ADD FUNCTIONS - virtual bool add_remote_tracker(const string &tracker, int sensor); - virtual bool add_remote_analog(const string &analog); - virtual bool add_remote_button(const string &button); - virtual bool add_remote_dial(const string &dial); - + INLINE static double convert_to_secs(struct timeval msg_time); + protected: - virtual int max_analog_channels(); + virtual PT(ClientDevice) make_device(TypeHandle device_type, + const string &device_name); - //Device polling functions - virtual void poll_tracker(const string &tracker); - virtual void poll_analog(const string &analog); - virtual void poll_button(const string &button); - virtual void poll_dial(const string &dial); + virtual bool disconnect_device(TypeHandle device_type, + const string &device_name, + ClientDevice *device); + + virtual void do_poll(); private: - //Private VRPN objects - typedef map VrpnTrackers; - typedef map VrpnAnalogs; - typedef map VrpnButtons; - typedef map VrpnDials; + PT(ClientDevice) make_tracker_device(const string &device_name); + PT(ClientDevice) make_button_device(const string &device_name); + PT(ClientDevice) make_analog_device(const string &device_name); + void disconnect_tracker_device(VrpnTrackerDevice *device); + void disconnect_button_device(VrpnButtonDevice *device); + void disconnect_analog_device(VrpnAnalogDevice *device); + VrpnTracker *get_tracker(const string &tracker_name); + void free_tracker(VrpnTracker *vrpn_tracker); + + VrpnButton *get_button(const string &button_name); + void free_button(VrpnButton *vrpn_button); + + VrpnAnalog *get_analog(const string &analog_name); + void free_analog(VrpnAnalog *vrpn_analog); + +private: + string _server_name; vrpn_Connection *_connection; - VrpnTrackers _vrpn_trackers; - VrpnAnalogs _vrpn_analogs; - VrpnButtons _vrpn_buttons; - VrpnDials _vrpn_dials; - //VRPN Callback functions. Each callback actually needs to be a - //pair of two functions, one a static and one not. The static is - //needed because we can't set member functions as callbacks (due to - //the implicity this pointer) and the non-static function is needed - //so that we can set the non-static data storage variables - //appropriately -private: - static void st_tracker_position(void *userdata, const vrpn_TRACKERCB info); - INLINE void tracker_position(const string &tracker, const vrpn_TRACKERCB info); + typedef map Trackers; + typedef map Buttons; + typedef map Analogs; - static void st_tracker_velocity(void *userdata, const vrpn_TRACKERVELCB info); - INLINE void tracker_velocity(const string &tracker, const vrpn_TRACKERVELCB info); + Trackers _trackers; + Buttons _buttons; + Analogs _analogs; - static void st_tracker_acceleration(void *userdata, const vrpn_TRACKERACCCB info); - INLINE void tracker_acceleration(const string &tracker, const vrpn_TRACKERACCCB info); - - static void st_analog(void *userdata, const vrpn_ANALOGCB info); - INLINE void analog(const string &analog, const vrpn_ANALOGCB info); - - static void st_button(void *userdata, const vrpn_BUTTONCB info); - INLINE void button(const string &button, const vrpn_BUTTONCB info); - - static void st_dial(void *userdata, const vrpn_DIALCB info); - INLINE void dial(const string &dial, const vrpn_DIALCB info); public: - static TypeHandle get_class_type( void ) { - return _type_handle; + static TypeHandle get_class_type() { + return _type_handle; } - static void init_type( void ) { + static void init_type() { ClientBase::init_type(); - register_type( _type_handle, "VrpnClient", - ClientBase::get_class_type() ); + register_type(_type_handle, "VrpnClient", + ClientBase::get_class_type()); } - virtual TypeHandle get_type( void ) const { + virtual TypeHandle get_type() const { return get_class_type(); } - virtual TypeHandle force_init_type() { - init_type(); - return get_class_type(); - } - + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + private: - static TypeHandle _type_handle; + static TypeHandle _type_handle; }; -INLINE double convert_to_secs(struct timeval msg_time); - #include "vrpnClient.I" #endif diff --git a/panda/src/vrpn/vrpnTracker.I b/panda/src/vrpn/vrpnTracker.I new file mode 100644 index 0000000000..ba8b87130e --- /dev/null +++ b/panda/src/vrpn/vrpnTracker.I @@ -0,0 +1,38 @@ +// Filename: vrpnTracker.I +// Created by: drose (25Jan01) +// +//////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////// +// Function: VrpnTracker::get_tracker_name +// Access: Public +// Description: Returns the name of the tracker device that was used +// to create this VrpnTracker. +//////////////////////////////////////////////////////////////////// +INLINE const string &VrpnTracker:: +get_tracker_name() const { + return _tracker_name; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnTracker::is_empty +// Access: Public +// Description: Returns true if no VrpnTrackerDevices reference this +// VrpnTracker, or false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool VrpnTracker:: +is_empty() const { + return _devices.empty(); +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnTracker::poll +// Access: Public +// Description: Polls the connected device. Normally you should not +// call this directly; this will be called by the +// VrpnClient. +//////////////////////////////////////////////////////////////////// +INLINE void VrpnTracker:: +poll() { + _tracker->mainloop(); +} diff --git a/panda/src/vrpn/vrpnTracker.cxx b/panda/src/vrpn/vrpnTracker.cxx new file mode 100644 index 0000000000..558a8da1b9 --- /dev/null +++ b/panda/src/vrpn/vrpnTracker.cxx @@ -0,0 +1,186 @@ +// Filename: vrpnTracker.cxx +// Created by: drose (25Jan01) +// +//////////////////////////////////////////////////////////////////// + +#include "vrpnTracker.h" +#include "vrpnTrackerDevice.h" +#include "vrpnClient.h" +#include "config_vrpn.h" + +#include + +#include + +//////////////////////////////////////////////////////////////////// +// Function: VrpnTracker::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +VrpnTracker:: +VrpnTracker(const string &tracker_name, vrpn_Connection *connection) : + _tracker_name(tracker_name) +{ + _tracker = new vrpn_Tracker_Remote(_tracker_name.c_str(), connection); + + _tracker->register_change_handler((void*)this, &vrpn_position_callback); + _tracker->register_change_handler((void*)this, &vrpn_velocity_callback); + _tracker->register_change_handler((void*)this, &vrpn_acceleration_callback); +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnTracker::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +VrpnTracker:: +~VrpnTracker() { + delete _tracker; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnTracker::mark +// Access: Public +// Description: Adds the indicated VrpnTrackerDevice to the list of +// devices that are sharing this VrpnTracker. +//////////////////////////////////////////////////////////////////// +void VrpnTracker:: +mark(VrpnTrackerDevice *device) { + if (vrpn_cat.is_debug()) { + vrpn_cat.debug() << *this << " marking " << *device << "\n"; + } + _devices.push_back(device); +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnTracker::unmark +// Access: Public +// Description: Removes the indicated VrpnTrackerDevice from the list +// of devices that are sharing this VrpnTracker. +//////////////////////////////////////////////////////////////////// +void VrpnTracker:: +unmark(VrpnTrackerDevice *device) { + if (vrpn_cat.is_debug()) { + vrpn_cat.debug() << *this << " unmarking " << *device << "\n"; + } + + Devices::iterator di = + find(_devices.begin(), _devices.end(), device); + + if (di != _devices.end()) { + _devices.erase(di); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnTracker::output +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void VrpnTracker:: +output(ostream &out) const { + out << _tracker_name; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnTracker::write +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void VrpnTracker:: +write(ostream &out, int indent_level) const { + indent(out, indent_level) + << get_tracker_name() << " (" + << _devices.size() << " devices)\n"; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnTracker::vrpn_position_callback +// Access: Private, Static +// Description: Receives the tracker positional data from the VRPN +// code and sends it to any interested +// VrpnTrackerDevices. +//////////////////////////////////////////////////////////////////// +void VrpnTracker:: +vrpn_position_callback(void *userdata, const vrpn_TRACKERCB info) { + VrpnTracker *self = (VrpnTracker *)userdata; + if (vrpn_cat.is_spam()) { + vrpn_cat.spam() + << *self << " position_callback\n"; + } + + Devices::iterator di; + for (di = self->_devices.begin(); di != self->_devices.end(); ++di) { + VrpnTrackerDevice *device = (*di); + if (device->get_sensor() == info.sensor && + device->get_data_type() == VrpnTrackerDevice::DT_position) { + device->lock(); + device->_data.set_time(VrpnClient::convert_to_secs(info.msg_time)); + device->_data.set_pos(LPoint3f(info.pos[0], info.pos[1], info.pos[2])); + device->_data.set_orient(LOrientationf(info.quat[0], info.quat[1], info.quat[2], info.quat[3])); + device->unlock(); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnTracker::vrpn_velocity_callback +// Access: Private, Static +// Description: Receives the tracker velocity data from the VRPN +// code and sends it to any interested +// VrpnTrackerDevices. +//////////////////////////////////////////////////////////////////// +void VrpnTracker:: +vrpn_velocity_callback(void *userdata, const vrpn_TRACKERVELCB info) { + VrpnTracker *self = (VrpnTracker *)userdata; + if (vrpn_cat.is_spam()) { + vrpn_cat.spam() + << *self << " velocity_callback\n"; + } + + Devices::iterator di; + for (di = self->_devices.begin(); di != self->_devices.end(); ++di) { + VrpnTrackerDevice *device = (*di); + if (device->get_sensor() == info.sensor && + device->get_data_type() == VrpnTrackerDevice::DT_velocity) { + device->lock(); + device->_data.set_time(VrpnClient::convert_to_secs(info.msg_time)); + device->_data.set_pos(LPoint3f(info.vel[0], info.vel[1], info.vel[2])); + device->_data.set_orient(LOrientationf(info.vel_quat[0], info.vel_quat[1], + info.vel_quat[2], info.vel_quat[3])); + device->_data.set_dt(info.vel_quat_dt); + device->unlock(); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnTracker::vrpn_acceleration_callback +// Access: Private, Static +// Description: Receives the tracker acceleration data from the VRPN +// code and sends it to any interested +// VrpnTrackerDevices. +//////////////////////////////////////////////////////////////////// +void VrpnTracker:: +vrpn_acceleration_callback(void *userdata, const vrpn_TRACKERACCCB info) { + VrpnTracker *self = (VrpnTracker *)userdata; + if (vrpn_cat.is_spam()) { + vrpn_cat.spam() + << *self << " acceleration_callback\n"; + } + + Devices::iterator di; + for (di = self->_devices.begin(); di != self->_devices.end(); ++di) { + VrpnTrackerDevice *device = (*di); + if (device->get_sensor() == info.sensor && + device->get_data_type() == VrpnTrackerDevice::DT_acceleration) { + device->lock(); + device->_data.set_time(VrpnClient::convert_to_secs(info.msg_time)); + device->_data.set_pos(LPoint3f(info.acc[0], info.acc[1], info.acc[2])); + device->_data.set_orient(LOrientationf(info.acc_quat[0], info.acc_quat[1], + info.acc_quat[2], info.acc_quat[3])); + device->_data.set_dt(info.acc_quat_dt); + device->unlock(); + } + } +} diff --git a/panda/src/vrpn/vrpnTracker.h b/panda/src/vrpn/vrpnTracker.h new file mode 100644 index 0000000000..4cdf0f4e1c --- /dev/null +++ b/panda/src/vrpn/vrpnTracker.h @@ -0,0 +1,72 @@ +// Filename: vrpnTracker.h +// Created by: drose (25Jan01) +// +//////////////////////////////////////////////////////////////////// + +#ifndef VRPNTRACKER_H +#define VRPNTRACKER_H + +#include + +#include "vrpn_interface.h" + +#include + +class VrpnTrackerDevice; + +//////////////////////////////////////////////////////////////////// +// Class : VrpnTracker +// Description : This is the actual interface to a particular VRPN +// tracker object, and all of its sensors. A pointer to +// this object is stored in the VrpnClient class for +// each differently-named VRPN tracker we connect to. +// +// The VRPN callbacks go here, which in turn get +// vectored out to any VrpnTrackerDevice objects that +// register with this. When the last VrpnTrackerDevice +// object unregisters, the VrpnTracker will be deleted +// by the VrpnClient. +// +// This class does not need to be exported from the DLL. +//////////////////////////////////////////////////////////////////// +class VrpnTracker { +public: + VrpnTracker(const string &tracker_name, vrpn_Connection *connection); + ~VrpnTracker(); + + INLINE const string &get_tracker_name() const; + INLINE bool is_empty() const; + + void mark(VrpnTrackerDevice *device); + void unmark(VrpnTrackerDevice *device); + + INLINE void poll(); + + void output(ostream &out) const; + void write(ostream &out, int indent_level = 0) const; + +private: + static void + vrpn_position_callback(void *userdata, const vrpn_TRACKERCB info); + static void + vrpn_velocity_callback(void *userdata, const vrpn_TRACKERVELCB info); + static void + vrpn_acceleration_callback(void *userdata, const vrpn_TRACKERACCCB info); + +private: + string _tracker_name; + vrpn_Tracker_Remote *_tracker; + + typedef vector Devices; + Devices _devices; +}; + +INLINE ostream &operator << (ostream &out, const VrpnTracker &tracker) { + tracker.output(out); + return out; +} + +#include "vrpnTracker.I" + +#endif + diff --git a/panda/src/vrpn/vrpnTrackerDevice.I b/panda/src/vrpn/vrpnTrackerDevice.I new file mode 100644 index 0000000000..8f201af9d6 --- /dev/null +++ b/panda/src/vrpn/vrpnTrackerDevice.I @@ -0,0 +1,42 @@ +// Filename: vrpnTrackerDevice.I +// Created by: drose (25Jan01) +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: VrpnTrackerDevice::get_sensor +// Access: Public +// Description: Returns the particular sensor index that this device +// wants to hear about from the VrpnTracker. +//////////////////////////////////////////////////////////////////// +INLINE int VrpnTrackerDevice:: +get_sensor() const { + return _sensor; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnTrackerDevice::get_data_type +// Access: Public +// Description: Returns the type of data this device represents from +// the VrpnTracker. This may be position, velocity, or +// acceleration. +//////////////////////////////////////////////////////////////////// +INLINE VrpnTrackerDevice::DataType VrpnTrackerDevice:: +get_data_type() const { + return _data_type; +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnTrackerDevice::get_vrpn_tracker +// Access: Public +// Description: Returns a pointer to the particular VrpnTracker this +// device gets its data from. This pointer may be +// shared with other VrpnTrackerDevice objects (each +// representing a different portion of the tracker +// data). +//////////////////////////////////////////////////////////////////// +INLINE VrpnTracker *VrpnTrackerDevice:: +get_vrpn_tracker() const { + return _vrpn_tracker; +} diff --git a/panda/src/vrpn/vrpnTrackerDevice.cxx b/panda/src/vrpn/vrpnTrackerDevice.cxx new file mode 100644 index 0000000000..cf10f1c48c --- /dev/null +++ b/panda/src/vrpn/vrpnTrackerDevice.cxx @@ -0,0 +1,35 @@ +// Filename: vrpnTrackerDevice.cxx +// Created by: drose (25Jan01) +// +//////////////////////////////////////////////////////////////////// + +#include "vrpnTrackerDevice.h" +#include "vrpnClient.h" + +TypeHandle VrpnTrackerDevice::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: VrpnTrackerDevice::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +VrpnTrackerDevice:: +VrpnTrackerDevice(VrpnClient *client, const string &device_name, + int sensor, VrpnTrackerDevice::DataType data_type, + VrpnTracker *vrpn_tracker) : + ClientTrackerDevice(client, device_name), + _sensor(sensor), + _data_type(data_type), + _vrpn_tracker(vrpn_tracker) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: VrpnTrackerDevice::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +VrpnTrackerDevice:: +~VrpnTrackerDevice() { + disconnect(); +} diff --git a/panda/src/vrpn/vrpnTrackerDevice.h b/panda/src/vrpn/vrpnTrackerDevice.h new file mode 100644 index 0000000000..8418991273 --- /dev/null +++ b/panda/src/vrpn/vrpnTrackerDevice.h @@ -0,0 +1,73 @@ +// Filename: vrpnTrackerDevice.h +// Created by: drose (25Jan01) +// +//////////////////////////////////////////////////////////////////// + +#ifndef VRPNTRACKERDEVICE_H +#define VRPNTRACKERDEVICE_H + +#include + +#include + +class VrpnClient; +class VrpnTracker; + +//////////////////////////////////////////////////////////////////// +// Class : VrpnTrackerDevice +// Description : The Panda interface to a VRPN tracker. This object +// will be returned by VrpnClient::make_device(), for +// attaching to a TrackerNode. +// +// It represents the data from just one particular +// sensor of a named VRPN tracker, and may reflect +// either the sensor's position, its velocity, or its +// acceleration. +// +// This class does not need to be exported from the DLL. +//////////////////////////////////////////////////////////////////// +class VrpnTrackerDevice : public ClientTrackerDevice { +public: + enum DataType { + DT_position, + DT_velocity, + DT_acceleration + }; + + VrpnTrackerDevice(VrpnClient *client, const string &device_name, + int sensor, DataType data_type, + VrpnTracker *vrpn_tracker); + virtual ~VrpnTrackerDevice(); + + INLINE int get_sensor() const; + INLINE DataType get_data_type() const; + INLINE VrpnTracker *get_vrpn_tracker() const; + +private: + int _sensor; + DataType _data_type; + VrpnTracker *_vrpn_tracker; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + ClientTrackerDevice::init_type(); + register_type(_type_handle, "VrpnTrackerDevice", + ClientTrackerDevice::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; + + friend class VrpnTracker; +}; + +#include "vrpnTrackerDevice.I" + +#endif diff --git a/panda/src/vrpn/vrpn_interface.h b/panda/src/vrpn/vrpn_interface.h new file mode 100644 index 0000000000..1be2e3a055 --- /dev/null +++ b/panda/src/vrpn/vrpn_interface.h @@ -0,0 +1,28 @@ +// Filename: vrpn_interface.h +// Created by: drose (25Jan01) +// +//////////////////////////////////////////////////////////////////// + +#ifndef VRPN_INTERFACE_H +#define VRPN_INTERFACE_H + +#include + +#ifdef CPPPARSER + // For correct interrogate parsing of UNC's vrpn library. + #ifdef WIN32_VC + #define _WIN32 + #define SOCKET int + #else + #define linux + typedef struct timeval timeval; + #endif +#endif + +#include +#include +#include +#include +#include + +#endif