*** empty log message ***

This commit is contained in:
David Rose 2001-01-26 22:31:00 +00:00
parent 6fdaa2a31b
commit 867fa370f4
63 changed files with 4034 additions and 1154 deletions

View File

@ -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

View File

@ -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());
}

View File

@ -1,78 +0,0 @@
// Filename: cerealboxNode.h
// Created by: jason (08Aug00)
//
////////////////////////////////////////////////////////////////////
#ifndef _ADINPUT_NODE
#define _ADINPUT_NODE
#include <pandabase.h>
#include <dataNode.h>
#include <nodeAttributes.h>
#include <doubleDataAttribute.h>
#include <doubleDataTransition.h>
#include <intDataAttribute.h>
#include <intDataTransition.h>
#include <doublePtrDataAttribute.h>
#include <doublePtrDataTransition.h>
#include <pointerTo.h>
#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

View File

@ -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 &copy) {
(*this) = copy;
}
////////////////////////////////////////////////////////////////////
// Function: AnalogData::Copy Assignment Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE AnalogData &AnalogData::
operator = (const AnalogData &copy) {
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;
}

View File

@ -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;

View File

@ -1,37 +0,0 @@
// Filename: analogData.h
// Created by: jason (04Aug00)
//
////////////////////////////////////////////////////////////////////
#ifndef ANALOG_DATA
#define ANALOG_DATA
#include <pandabase.h>
#include <vector_double.h>
class EXPCL_PANDA AnalogData {
public:
INLINE AnalogData();
INLINE ~AnalogData();
INLINE AnalogData(const AnalogData &copy);
INLINE AnalogData &operator = (const AnalogData &copy);
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

View File

@ -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;
}

View File

@ -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());
}

View File

@ -0,0 +1,101 @@
// Filename: analogNode.h
// Created by: drose (26Jan01)
//
////////////////////////////////////////////////////////////////////
#ifndef ANALOGNODE_H
#define ANALOGNODE_H
#include <pandabase.h>
#include "clientBase.h"
#include "clientAnalogDevice.h"
#include <dataNode.h>
#include <nodeAttributes.h>
#include <vec3DataTransition.h>
#include <vec3DataAttribute.h>
////////////////////////////////////////////////////////////////////
// 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

View File

@ -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 &copy) {
(*this) = copy;
}
////////////////////////////////////////////////////////////////////
// Function: ButtonData::Copy Assignment Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE ButtonData &ButtonData::
operator = (const ButtonData &copy) {
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;
}

View File

@ -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;

View File

@ -1,29 +0,0 @@
// Filename: buttonData.h
// Created by: jason (07Aug00)
//
////////////////////////////////////////////////////////////////////
#ifndef BUTTON_DATA
#define BUTTON_DATA
#include <pandabase.h>
#include <vector_float.h>
class EXPCL_PANDA ButtonData {
public:
INLINE ButtonData();
INLINE ButtonData(const ButtonData &copy);
INLINE ButtonData &operator = (const ButtonData &copy);
INLINE static const ButtonData &none();
double btime;
int button_id;
int state;
private:
static ButtonData _none;
};
#include "buttonData.I"
#endif

View File

@ -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);
}

View File

@ -0,0 +1,132 @@
// Filename: buttonNode.cxx
// Created by: drose (31Dec69)
//
////////////////////////////////////////////////////////////////////
#include "buttonNode.h"
#include "config_device.h"
#include <buttonEventDataTransition.h>
////////////////////////////////////////////////////////////////////
// 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());
}

View File

@ -0,0 +1,84 @@
// Filename: buttonNode.h
// Created by: drose (31Dec69)
//
////////////////////////////////////////////////////////////////////
#ifndef BUTTONNODE_H
#define BUTTONNODE_H
#include <pandabase.h>
#include "clientBase.h"
#include "clientButtonDevice.h"
#include <dataNode.h>
#include <nodeAttributes.h>
////////////////////////////////////////////////////////////////////
// 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

View File

@ -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;
}
}

View File

@ -0,0 +1,66 @@
// Filename: clientAnalogDevice.cxx
// Created by: drose (26Jan01)
//
////////////////////////////////////////////////////////////////////
#include "clientAnalogDevice.h"
#include <indent.h>
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";
}
}

View File

@ -0,0 +1,75 @@
// Filename: clientAnalogDevice.h
// Created by: drose (26Jan01)
//
////////////////////////////////////////////////////////////////////
#ifndef CLIENTANALOGDEVICE_H
#define CLIENTANALOGDEVICE_H
#include <pandabase.h>
#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<AnalogState> 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

View File

@ -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;
}

View File

@ -8,18 +8,19 @@
TypeHandle ClientBase::_type_handle;
#include <algorithm>
////////////////////////////////////////////////////////////////////
// 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));
}
}

View File

@ -3,145 +3,102 @@
//
////////////////////////////////////////////////////////////////////
#ifndef _CLIENT_BASE
#define _CLIENT_BASE
#ifndef CLIENTBASE_H
#define CLIENTBASE_H
#include <pandabase.h>
#include "trackerData.h"
#include "analogData.h"
#include "buttonData.h"
#include "dialData.h"
#include "clientDevice.h"
#include <typedReferenceCount.h>
#include <luse.h>
#include <vector_string.h>
#include <vector_int.h>
#include <clockObject.h>
#include <pointerTo.h>
#ifdef HAVE_IPC
#include <ipc_mutex.h>
#include <ipc_condition.h>
#include <ipc_thread.h>
#endif
#include <map>
////////////////////////////////////////////////////////////////////
// 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<string, ClientDevice *> DevicesByName;
typedef map<TypeHandle, DevicesByName> 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

View File

@ -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;
}

View File

@ -0,0 +1,153 @@
// Filename: clientButtonDevice.cxx
// Created by: drose (26Jan01)
//
////////////////////////////////////////////////////////////////////
#include "clientButtonDevice.h"
#include <indent.h>
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";
}
}

View File

@ -0,0 +1,92 @@
// Filename: clientButtonDevice.h
// Created by: drose (26Jan01)
//
////////////////////////////////////////////////////////////////////
#ifndef CLIENTBUTTONDEVICE_H
#define CLIENTBUTTONDEVICE_H
#include <pandabase.h>
#include "clientDevice.h"
#include <buttonHandle.h>
#include <buttonEvent.h>
#include <buttonEventDataAttribute.h>
////////////////////////////////////////////////////////////////////
// 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<ButtonState> 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

View File

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

View File

@ -0,0 +1,104 @@
// Filename: clientDevice.cxx
// Created by: drose (25Jan01)
//
////////////////////////////////////////////////////////////////////
#include "clientDevice.h"
#include "clientBase.h"
#include <indent.h>
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";
}

View File

@ -0,0 +1,85 @@
// Filename: clientDevice.h
// Created by: drose (25Jan01)
//
////////////////////////////////////////////////////////////////////
#ifndef CLIENTDEVICE_H
#define CLIENTDEVICE_H
#include <pandabase.h>
#include <typedReferenceCount.h>
#ifdef HAVE_IPC
#include <ipc_mutex.h>
#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

View File

@ -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;
}

View File

@ -0,0 +1,8 @@
// Filename: clientTrackerDevice.cxx
// Created by: drose (25Jan01)
//
////////////////////////////////////////////////////////////////////
#include "clientTrackerDevice.h"
TypeHandle ClientTrackerDevice::_type_handle;

View File

@ -0,0 +1,50 @@
// Filename: clientTrackerDevice.h
// Created by: drose (25Jan01)
//
////////////////////////////////////////////////////////////////////
#ifndef CLIENTTRACKERDEVICE_H
#define CLIENTTRACKERDEVICE_H
#include <pandabase.h>
#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

View File

@ -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 <dconfig.h>
@ -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();
}

View File

@ -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 &copy) {
}
////////////////////////////////////////////////////////////////////
// Function: TrackerData::Copy Assignment Operator
// Function: TrackerData::clear
// Access: Public
// Description:
// Description: Removes all data from the structure.
////////////////////////////////////////////////////////////////////
INLINE TrackerData &TrackerData::
operator = (const TrackerData &copy) {
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;
}

View File

@ -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 &copy) {
_flags = copy._flags;
_time = copy._time;
_pos = copy._pos;
_orient = copy._orient;
_dt = copy._dt;
}

View File

@ -3,36 +3,54 @@
//
////////////////////////////////////////////////////////////////////
#ifndef TRACKER_DATA
#define TRACKER_DATA
#ifndef TRACKERDATA_H
#define TRACKERDATA_H
#include <pandabase.h>
#include <luse.h>
////////////////////////////////////////////////////////////////////
// Class : TrackerData
// Description : Stores the kinds of data that a tracker might output.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA TrackerData {
public:
INLINE TrackerData();
INLINE TrackerData(const TrackerData &copy);
INLINE TrackerData &operator = (const TrackerData &copy);
void operator = (const TrackerData &copy);
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"

View File

@ -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;
}

View File

@ -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());
}

View File

@ -3,73 +3,59 @@
//
////////////////////////////////////////////////////////////////////
#ifndef _TRACKER_NODE
#define _TRACKER_NODE
#ifndef TRACKERNODE_H
#define TRACKERNODE_H
#include <pandabase.h>
#include <dataNode.h>
#include <nodeAttributes.h>
#include <doubleDataAttribute.h>
#include <doubleDataTransition.h>
#include <vec3DataAttribute.h>
#include <vec3DataTransition.h>
#include <vec3DataAttribute.h>
#include <vec4DataTransition.h>
#include <vec4DataAttribute.h>
#include <pointerTo.h>
#include "clientBase.h"
#include "trackerData.h"
#include "clientTrackerDevice.h"
#include <dataNode.h>
#include <matrixDataTransition.h>
#include <matrixDataAttribute.h>
#include <nodeAttributes.h>
#include <luse.h>
#include <lmatrix.h>
#include <pointerTo.h>
////////////////////////////////////////////////////////////////////
// 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

View File

@ -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:

View File

@ -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);

View File

@ -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

View File

@ -4,7 +4,10 @@
////////////////////////////////////////////////////////////////////
#include "config_vrpn.h"
#include "vrpnAnalogDevice.h"
#include "vrpnButtonDevice.h"
#include "vrpnClient.h"
#include "vrpnTrackerDevice.h"
#include <dconfig.h>
@ -13,5 +16,8 @@ NotifyCategoryDef(vrpn, "");
ConfigureFn(config_vrpn) {
VrpnAnalogDevice::init_type();
VrpnButtonDevice::init_type();
VrpnClient::init_type();
VrpnTrackerDevice::init_type();
}

View File

@ -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();
}

View File

@ -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 <indent.h>
#include <algorithm>
////////////////////////////////////////////////////////////////////
// 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();
}
}

View File

@ -0,0 +1,68 @@
// Filename: vrpnAnalog.h
// Created by: drose (26Jan01)
//
////////////////////////////////////////////////////////////////////
#ifndef VRPNANALOG_H
#define VRPNANALOG_H
#include <pandabase.h>
#include "vrpn_interface.h"
#include <vector>
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<VrpnAnalogDevice *> Devices;
Devices _devices;
};
INLINE ostream &operator << (ostream &out, const VrpnAnalog &analog) {
analog.output(out);
return out;
}
#include "vrpnAnalog.I"
#endif

View File

@ -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;
}

View File

@ -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();
}

View File

@ -0,0 +1,57 @@
// Filename: vrpnAnalogDevice.h
// Created by: drose (26Jan01)
//
////////////////////////////////////////////////////////////////////
#ifndef VRPNANALOGDEVICE_H
#define VRPNANALOGDEVICE_H
#include <pandabase.h>
#include <clientAnalogDevice.h>
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

View File

@ -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();
}

View File

@ -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 <indent.h>
#include <algorithm>
////////////////////////////////////////////////////////////////////
// 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();
}
}

View File

@ -0,0 +1,68 @@
// Filename: vrpnButton.h
// Created by: drose (26Jan01)
//
////////////////////////////////////////////////////////////////////
#ifndef VRPNBUTTON_H
#define VRPNBUTTON_H
#include <pandabase.h>
#include "vrpn_interface.h"
#include <vector>
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<VrpnButtonDevice *> Devices;
Devices _devices;
};
INLINE ostream &operator << (ostream &out, const VrpnButton &button) {
button.output(out);
return out;
}
#include "vrpnButton.I"
#endif

View File

@ -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;
}

View File

@ -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();
}

View File

@ -0,0 +1,57 @@
// Filename: vrpnButtonDevice.h
// Created by: drose (26Jan01)
//
////////////////////////////////////////////////////////////////////
#ifndef VRPNBUTTONDEVICE_H
#define VRPNBUTTONDEVICE_H
#include <pandabase.h>
#include <clientButtonDevice.h>
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

View File

@ -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

View File

@ -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 <string_utils.h>
#include <indent.h>
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 <datagram.h>
#include <datagramIterator.h>
@ -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

View File

@ -3,110 +3,99 @@
//
////////////////////////////////////////////////////////////////////
#ifndef VRPN_CLIENT
#define VRPN_CLIENT
#ifndef VRPNCLIENT_H
#define VRPNCLIENT_H
#include <pandabase.h>
#include <clientBase.h>
#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 <vrpn_Connection.h>
#include <vrpn_Tracker.h>
#include <vrpn_Analog.h>
#include <vrpn_Button.h>
#include <vrpn_Dial.h>
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 <string, vrpn_Tracker*> VrpnTrackers;
typedef map <string, vrpn_Analog*> VrpnAnalogs;
typedef map <string, vrpn_Button*> VrpnButtons;
typedef map <string, vrpn_Dial*> 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<string, VrpnTracker *> Trackers;
typedef map<string, VrpnButton *> Buttons;
typedef map<string, VrpnAnalog *> 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

View File

@ -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();
}

View File

@ -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 <indent.h>
#include <algorithm>
////////////////////////////////////////////////////////////////////
// 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();
}
}
}

View File

@ -0,0 +1,72 @@
// Filename: vrpnTracker.h
// Created by: drose (25Jan01)
//
////////////////////////////////////////////////////////////////////
#ifndef VRPNTRACKER_H
#define VRPNTRACKER_H
#include <pandabase.h>
#include "vrpn_interface.h"
#include <vector>
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<VrpnTrackerDevice *> Devices;
Devices _devices;
};
INLINE ostream &operator << (ostream &out, const VrpnTracker &tracker) {
tracker.output(out);
return out;
}
#include "vrpnTracker.I"
#endif

View File

@ -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;
}

View File

@ -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();
}

View File

@ -0,0 +1,73 @@
// Filename: vrpnTrackerDevice.h
// Created by: drose (25Jan01)
//
////////////////////////////////////////////////////////////////////
#ifndef VRPNTRACKERDEVICE_H
#define VRPNTRACKERDEVICE_H
#include <pandabase.h>
#include <clientTrackerDevice.h>
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

View File

@ -0,0 +1,28 @@
// Filename: vrpn_interface.h
// Created by: drose (25Jan01)
//
////////////////////////////////////////////////////////////////////
#ifndef VRPN_INTERFACE_H
#define VRPN_INTERFACE_H
#include <pandabase.h>
#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_Connection.h>
#include <vrpn_Tracker.h>
#include <vrpn_Analog.h>
#include <vrpn_Button.h>
#include <vrpn_Dial.h>
#endif