Browse Source

*** empty log message ***

David Rose 25 years ago
parent
commit
fe2f34c925

+ 9 - 4
panda/src/device/Sources.pp

@@ -13,10 +13,12 @@
     clientBase.I clientBase.cxx clientBase.h \
     clientButtonDevice.I clientButtonDevice.cxx clientButtonDevice.h \
     clientDevice.I clientDevice.cxx clientDevice.h \
+    clientDialDevice.I clientDialDevice.cxx clientDialDevice.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 \
+    dialNode.I dialNode.h dialNode.cxx \
+    mouse.cxx mouse.h \
+    trackerData.I trackerData.cxx trackerData.h \
     trackerNode.I trackerNode.cxx trackerNode.h
 
   #define INSTALL_HEADERS \
@@ -26,9 +28,12 @@
     clientBase.I clientBase.h \
     clientButtonDevice.I clientButtonDevice.h \
     clientDevice.I clientDevice.h \
+    clientDialDevice.I clientDialDevice.h \
     clientTrackerDevice.I clientTrackerDevice.h \
-    config_device.h dialData.I dialData.h mouse.h \
-    trackerData.I trackerData.h trackerNode.I trackerNode.h
+    config_device.h mouse.h \
+    dialNode.I dialNode.h \
+    trackerData.I trackerData.h \
+    trackerNode.I trackerNode.h
 
   #define IGATESCAN all
 

+ 12 - 3
panda/src/device/analogNode.I

@@ -35,7 +35,10 @@ is_valid() const {
 ////////////////////////////////////////////////////////////////////
 INLINE int AnalogNode::
 get_num_controls() const {
-  return _analog->get_num_controls();
+  _analog->lock();
+  int result = _analog->get_num_controls();
+  _analog->unlock();
+  return result;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -48,7 +51,10 @@ get_num_controls() const {
 ////////////////////////////////////////////////////////////////////
 INLINE double AnalogNode::
 get_control_state(int index) const {
-  return _analog->get_control_state(index);
+  _analog->lock();
+  double result = _analog->get_control_state(index);
+  _analog->unlock();
+  return result;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -60,7 +66,10 @@ get_control_state(int index) const {
 ////////////////////////////////////////////////////////////////////
 INLINE bool AnalogNode::
 is_control_known(int index) const {
-  return _analog->is_control_known(index);
+  _analog->lock();
+  bool result = _analog->is_control_known(index);
+  _analog->unlock();
+  return result;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 8 - 3
panda/src/device/analogNode.cxx

@@ -67,7 +67,9 @@ write(ostream &out, int indent_level) const {
   DataNode::write(out, indent_level);
 
   if (_analog != (ClientAnalogDevice *)NULL) {
+    _analog->lock();
     _analog->write_controls(out, indent_level + 2);
+    _analog->unlock();
   }
 }
 
@@ -83,15 +85,18 @@ transmit_data(NodeAttributes &data) {
 
     LPoint3f out(0.0, 0.0, 0.0);
 
+    _analog->lock();
     for (int i = 0; i < max_outputs; i++) {
-      if (_outputs[i]._index >= 0 && is_control_known(_outputs[i]._index)) {
+      if (_outputs[i]._index >= 0 && 
+	  _analog->is_control_known(_outputs[i]._index)) {
 	if (_outputs[i]._flip) {
-	  out[i] = -get_control_state(_outputs[i]._index);
+	  out[i] = -_analog->get_control_state(_outputs[i]._index);
 	} else {
-	  out[i] = get_control_state(_outputs[i]._index);
+	  out[i] = _analog->get_control_state(_outputs[i]._index);
 	}
       }
     }
+    _analog->unlock();
     _xyz->set_value(out);
   }
 

+ 18 - 4
panda/src/device/buttonNode.I

@@ -27,7 +27,10 @@ is_valid() const {
 ////////////////////////////////////////////////////////////////////
 INLINE int ButtonNode::
 get_num_buttons() const {
-  return _button->get_num_buttons();
+  _button->lock();
+  int result = _button->get_num_buttons();
+  _button->unlock();
+  return result;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -46,7 +49,9 @@ get_num_buttons() const {
 ////////////////////////////////////////////////////////////////////
 INLINE void ButtonNode::
 set_button_map(int index, ButtonHandle button) {
+  _button->lock();
   _button->set_button_map(index, button);
+  _button->unlock();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -59,7 +64,10 @@ set_button_map(int index, ButtonHandle button) {
 ////////////////////////////////////////////////////////////////////
 INLINE ButtonHandle ButtonNode::
 get_button_map(int index) const {
-  return _button->get_button_map(index);
+  _button->lock();
+  ButtonHandle result = _button->get_button_map(index);
+  _button->unlock();
+  return result;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -71,7 +79,10 @@ get_button_map(int index) const {
 ////////////////////////////////////////////////////////////////////
 INLINE bool ButtonNode::
 get_button_state(int index) const {
-  return _button->get_button_state(index);
+  _button->lock();
+  bool result = _button->get_button_state(index);
+  _button->unlock();
+  return result;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -83,5 +94,8 @@ get_button_state(int index) const {
 ////////////////////////////////////////////////////////////////////
 INLINE bool ButtonNode::
 is_button_known(int index) const {
-  return _button->is_button_known(index);
+  _button->lock();
+  bool result = _button->is_button_known(index);
+  _button->unlock();
+  return result;
 }

+ 4 - 0
panda/src/device/buttonNode.cxx

@@ -72,7 +72,9 @@ output(ostream &out) const {
 
   if (_button != (ClientButtonDevice *)NULL) {
     out << " (";
+    _button->lock();
     _button->output_buttons(out);
+    _button->unlock();
     out << ")";
   }
 }
@@ -87,7 +89,9 @@ write(ostream &out, int indent_level) const {
   DataNode::write(out, indent_level);
 
   if (_button != (ClientButtonDevice *)NULL) {
+    _button->lock();
     _button->write_buttons(out, indent_level + 2);
+    _button->unlock();
   }
 }
 

+ 5 - 0
panda/src/device/clientDevice.cxx

@@ -56,13 +56,18 @@ ClientDevice::
 //               (and it is probably a mistake to do so); it will
 //               automatically be called when the ClientDevice object
 //               destructs.
+//
+//               The lock should *not* be held while this call is
+//               made; it will explicitly grab the lock itself.
 ////////////////////////////////////////////////////////////////////
 void ClientDevice::
 disconnect() {
   if (_is_connected) {
+    lock();
     bool disconnected =
       _client->disconnect_device(_device_type, _device_name, this);
     _is_connected = false;
+    unlock();
     nassertv(disconnected);
   }
 }

+ 92 - 0
panda/src/device/clientDialDevice.I

@@ -0,0 +1,92 @@
+// Filename: clientDialDevice.I
+// Created by:  drose (26Jan01)
+// 
+////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////
+//     Function: ClientDialDevice::DialState::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE ClientDialDevice::DialState::
+DialState() :
+  _offset(0.0),
+  _known(false)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ClientDialDevice::Constructor
+//       Access: Protected
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE ClientDialDevice::
+ClientDialDevice(ClientBase *client, const string &device_name):
+  ClientDevice(client, get_class_type(), device_name)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ClientDialDevice::get_num_dials
+//       Access: Public
+//  Description: Returns the number of dial dials known to the
+//               ClientDialDevice.  This number may change as
+//               more dials are discovered.
+////////////////////////////////////////////////////////////////////
+INLINE int ClientDialDevice::
+get_num_dials() const {
+  return _dials.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ClientDialDevice::push_dial
+//       Access: Public
+//  Description: Marks that the dial has been offset by the indicated
+//               amount.  It is the user's responsibility to ensure
+//               that this call is protected within lock().
+////////////////////////////////////////////////////////////////////
+INLINE void ClientDialDevice::
+push_dial(int index, double offset) {
+  ensure_dial_index(index);
+  nassertv(index >= 0 && index < (int)_dials.size());
+  _dials[index]._offset += offset;
+  _dials[index]._known = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ClientDialDevice::read_dial
+//       Access: Public
+//  Description: Returns the number of complete revolutions of the
+//               dial since the last time read_dial() was called.
+//               This is a destructive operation; it is not possible
+//               to read the dial without resetting the counter.
+//
+//               It is the user's responsibility to ensure that this
+//               call is protected within lock().
+////////////////////////////////////////////////////////////////////
+INLINE double ClientDialDevice::
+read_dial(int index) {
+  if (index >= 0 && index < (int)_dials.size()) {
+    double result = _dials[index]._offset;
+    _dials[index]._offset = 0.0;
+    return result;
+  } else {
+    return 0.0;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ClientDialDevice::is_dial_known
+//       Access: Public
+//  Description: Returns true if the state of the indicated dial
+//               dial is known, or false if we have never heard
+//               anything about this particular dial.
+////////////////////////////////////////////////////////////////////
+INLINE bool ClientDialDevice::
+is_dial_known(int index) const {
+  if (index >= 0 && index < (int)_dials.size()) {
+    return _dials[index]._known;
+  } else {
+    return false;
+  }
+}

+ 29 - 0
panda/src/device/clientDialDevice.cxx

@@ -0,0 +1,29 @@
+// Filename: clientDialDevice.cxx
+// Created by:  drose (26Jan01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "clientDialDevice.h"
+
+#include <indent.h>
+
+TypeHandle ClientDialDevice::_type_handle;
+
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ClientDialDevice::ensure_dial_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 ClientDialDevice::
+ensure_dial_index(int index) {
+  nassertv(index >= 0);
+
+  _dials.reserve(index + 1);
+  while ((int)_dials.size() <= index) {
+    _dials.push_back(DialState());
+  }
+}

+ 73 - 0
panda/src/device/clientDialDevice.h

@@ -0,0 +1,73 @@
+// Filename: clientDialDevice.h
+// Created by:  drose (26Jan01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef CLIENTDIALDEVICE_H
+#define CLIENTDIALDEVICE_H
+
+#include <pandabase.h>
+
+#include "clientDevice.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : ClientDialDevice
+// Description : A device, attached to the ClientBase by a
+//               DialNode, that records the data from a single
+//               named dial device.  The named device can contain
+//               any number of dials, numbered in sequence beginning
+//               at zero.
+//
+//               A dial is a rotating device that does not have
+//               stops--it can keep rotating any number of times.
+//               Therefore it does not have a specific position at any
+//               given time, unlike an AnalogDevice.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA ClientDialDevice : public ClientDevice {
+protected:
+  INLINE ClientDialDevice(ClientBase *client, const string &device_name);
+
+public:
+  INLINE int get_num_dials() const;
+
+  INLINE void push_dial(int index, double offset);
+  INLINE double read_dial(int index);
+  INLINE bool is_dial_known(int index) const;
+
+private:
+  void ensure_dial_index(int index);
+
+protected:
+  class DialState {
+  public:
+    INLINE DialState();
+
+    double _offset;
+    bool _known;
+  };
+
+  typedef vector<DialState> Dials;
+  Dials _dials;
+
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    ClientDevice::init_type();
+    register_type(_type_handle, "ClientDialDevice",
+                  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 "clientDialDevice.I"
+
+#endif

+ 5 - 1
panda/src/device/config_device.cxx

@@ -10,7 +10,9 @@
 #include "clientBase.h"
 #include "clientButtonDevice.h"
 #include "clientDevice.h"
+#include "clientDialDevice.h"
 #include "clientTrackerDevice.h"
+#include "dialNode.h"
 #include "mouse.h"
 #include "trackerNode.h"
 
@@ -19,7 +21,7 @@
 Configure(config_device);
 NotifyCategoryDef(device, "");
 
-const bool asynchronous_clients = config_device.GetBool("asynchronous-clients", false);
+const bool asynchronous_clients = config_device.GetBool("asynchronous-clients", true);
 
 ConfigureFn(config_device) {
   init_libdevice();
@@ -47,7 +49,9 @@ init_libdevice() {
   ClientBase::init_type();
   ClientButtonDevice::init_type();
   ClientDevice::init_type();
+  ClientDialDevice::init_type();
   ClientTrackerDevice::init_type();
+  DialNode::init_type();
   MouseAndKeyboard::init_type();
   TrackerNode::init_type();
 }

+ 0 - 49
panda/src/device/dialData.I

@@ -1,49 +0,0 @@
-// Filename: dialData.I
-// Created by:  jason (07Aug00)
-// 
-////////////////////////////////////////////////////////////////////
-
-////////////////////////////////////////////////////////////////////
-//     Function: DialData::Default Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE DialData::
-DialData() :
-  dtime(0), dial_id(0), change(0)
-{
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DialData::Copy Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE DialData::
-DialData(const DialData &copy) {
-  (*this) = copy;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DialData::Copy Assignment Operator
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE DialData &DialData::
-operator = (const DialData &copy) {
-  dtime = copy.dtime;
-  dial_id = copy.dial_id;
-  change = copy.change;
-
-  return *this;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DialData::none
-//       Access: Public, Static
-//  Description: Returns an empty DialData object
-////////////////////////////////////////////////////////////////////
-INLINE const DialData &DialData::
-none() {
- return _none; 
-}

+ 0 - 9
panda/src/device/dialData.cxx

@@ -1,9 +0,0 @@
-// Filename: dialData.cxx
-// Created by:  jason (04Aug00)
-// 
-////////////////////////////////////////////////////////////////////
-
-#include "dialData.h"
-
-// This is initialized to zero by static initialization.
-DialData DialData::_none;

+ 0 - 29
panda/src/device/dialData.h

@@ -1,29 +0,0 @@
-// Filename: dialData.h
-// Created by:  jason (07Aug00)
-// 
-////////////////////////////////////////////////////////////////////
-
-#ifndef DIAL_DATA
-#define DIAL_DATA
-
-#include <pandabase.h>
-#include <vector_float.h>
-
-class EXPCL_PANDA DialData {
-public:
-  INLINE DialData();
-  INLINE DialData(const DialData &copy);
-  INLINE DialData &operator = (const DialData &copy);
-
-  INLINE static const DialData &none();
-
-  double dtime;
-  int dial_id;
-  float change;
-private:
-  static DialData _none;
-};
-
-#include "dialData.I"
-
-#endif

+ 61 - 0
panda/src/device/dialNode.I

@@ -0,0 +1,61 @@
+// Filename: dialNode.I
+// Created by:  drose (26Jan01)
+// 
+////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////
+//     Function: DialNode::is_valid
+//       Access: Public
+//  Description: Returns true if the DialNode is valid and
+//               connected to a server, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool DialNode::
+is_valid() const {
+  return (_dial != (ClientDialDevice *)NULL) && _dial->is_connected();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DialNode::get_num_dials
+//       Access: Public
+//  Description: Returns the number of dial dials known to the
+//               DialNode.  This number may change as more dials
+//               are discovered.
+////////////////////////////////////////////////////////////////////
+INLINE int DialNode::
+get_num_dials() const {
+  _dial->lock();
+  int result = _dial->get_num_dials();
+  _dial->unlock();
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DialNode::read_dial
+//       Access: Public
+//  Description: Returns the number of complete revolutions of the
+//               dial since the last time read_dial() was called.
+//               This is a destructive operation; it is not possible
+//               to read the dial without resetting the counter.
+////////////////////////////////////////////////////////////////////
+INLINE double DialNode::
+read_dial(int index) {
+  _dial->lock();
+  double result = _dial->read_dial(index);
+  _dial->unlock();
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DialNode::is_dial_known
+//       Access: Public
+//  Description: Returns true if the state of the indicated dial
+//               dial is known, or false if we have never heard
+//               anything about this particular dial.
+////////////////////////////////////////////////////////////////////
+INLINE bool DialNode::
+is_dial_known(int index) const {
+  _dial->lock();
+  bool result = _dial->is_dial_known(index);
+  _dial->unlock();
+  return result;
+}

+ 82 - 0
panda/src/device/dialNode.cxx

@@ -0,0 +1,82 @@
+// Filename: dialNode.cxx
+// Created by:  drose (26Jan01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "dialNode.h"
+#include "config_device.h"
+
+////////////////////////////////////////////////////////////////////
+// Static variables
+////////////////////////////////////////////////////////////////////
+TypeHandle DialNode::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: DialNode::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+DialNode::
+DialNode(ClientBase *client, const string &device_name) :
+  DataNode(device_name)
+{
+  nassertv(client != (ClientBase *)NULL);
+  PT(ClientDevice) device = 
+    client->get_device(ClientDialDevice::get_class_type(), device_name);
+
+  if (device == (ClientDevice *)NULL) {
+    device_cat.warning()
+      << "Unable to open dial device " << device_name << "\n";
+    return;
+  }
+
+  if (!device->is_of_type(ClientDialDevice::get_class_type())) {
+    device_cat.error()
+      << "Inappropriate device type " << device->get_type()
+      << " created; expected a ClientDialDevice.\n";
+    return;
+  }
+
+  _dial = DCAST(ClientDialDevice, device);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DialNode::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+DialNode::
+~DialNode() {
+  // When the _dial pointer destructs, the ClientDialDevice
+  // disconnects itself from the ClientBase, and everything that needs
+  // to get turned off does.  Magic.
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DialNode::transmit_data
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+void DialNode::
+transmit_data(NodeAttributes &data) {
+  if (is_valid()) {
+    _dial->poll();
+
+    // Not clear yet what we should be transmitting.
+  }
+
+  data = _attrib;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DialNode::init_type
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+void DialNode::
+init_type() {
+  DataNode::init_type();
+  register_type(_type_handle, "DialNode",
+		DataNode::get_class_type());
+}
+

+ 72 - 0
panda/src/device/dialNode.h

@@ -0,0 +1,72 @@
+// Filename: dialNode.h
+// Created by:  drose (26Jan01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef DIALNODE_H
+#define DIALNODE_H
+
+#include <pandabase.h>
+
+#include "clientBase.h"
+#include "clientDialDevice.h"
+
+#include <dataNode.h>
+#include <nodeAttributes.h>
+
+
+////////////////////////////////////////////////////////////////////
+//       Class : DialNode
+// Description : This is the primary interface to infinite dial type
+//               devices associated with a ClientBase.  This creates a
+//               node that connects to the named dial device, if it
+//               exists, and provides hooks to the user to read the
+//               state of any of the sequentially numbered dial
+//               controls associated with that device.
+//               
+//               A dial is a rotating device that does not have
+//               stops--it can keep rotating any number of times.
+//               Therefore it does not have a specific position at any
+//               given time, unlike an AnalogDevice.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA DialNode : public DataNode {
+PUBLISHED:
+  DialNode(ClientBase *client, const string &device_name);
+  virtual ~DialNode();
+
+  INLINE bool is_valid() const;
+
+  INLINE int get_num_dials() const;
+
+  INLINE double read_dial(int index);
+  INLINE bool is_dial_known(int index) const;
+
+////////////////////////////////////////////////////////////////////
+// From parent class DataNode
+////////////////////////////////////////////////////////////////////
+public:
+  virtual void
+  transmit_data(NodeAttributes &data);
+
+  NodeAttributes _attrib;
+
+private:
+  PT(ClientDialDevice) _dial;
+
+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 "dialNode.I"
+
+#endif

+ 5 - 4
panda/src/device/trackerNode.h

@@ -22,10 +22,11 @@
 
 ////////////////////////////////////////////////////////////////////
 //       Class : TrackerNode
-// 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.
+// Description : This is the primary interface to a Tracker object
+//               associated with a ClientBase.  It reads the position
+//               and orientation information from the tracker and
+//               makes it available as a transformation on the data
+//               graph.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA TrackerNode : public DataNode {
 PUBLISHED:

+ 2 - 2
panda/src/tform/Sources.pp

@@ -12,13 +12,13 @@
     driveInterface.cxx driveInterface.h mouseWatcher.I mouseWatcher.cxx \
     mouseWatcher.h mouseWatcherRegion.I mouseWatcherRegion.cxx \
     mouseWatcherRegion.h planarSlider.cxx planarSlider.h trackball.cxx \
-    trackball.h trackerTransform.cxx trackerTransform.h \
+    trackball.h \
     transform2sg.cxx transform2sg.h
 
   #define INSTALL_HEADERS \
     buttonThrower.h driveInterface.h mouseWatcher.I mouseWatcher.h \
     mouseWatcherRegion.I mouseWatcherRegion.h planarSlider.h \
-    trackball.h trackerTransform.h transform2sg.h
+    trackball.h transform2sg.h
 
   #define IGATESCAN all
 

+ 0 - 2
panda/src/tform/config_tform.cxx

@@ -11,7 +11,6 @@
 #include "planarSlider.h"
 #include "trackball.h"
 #include "transform2sg.h"
-#include "trackerTransform.h"
 
 #include <dconfig.h>
 
@@ -38,5 +37,4 @@ ConfigureFn(config_tform) {
   PlanarSlider::init_type();
   Trackball::init_type();
   Transform2SG::init_type();
-  TrackerTransform::init_type();
 }

+ 0 - 82
panda/src/tform/trackerTransform.cxx

@@ -1,82 +0,0 @@
-// Filename: trackerTransform.cxx
-// Created by:  jason (08Aug00)
-// 
-////////////////////////////////////////////////////////////////////
-
-#include <pandabase.h>
-
-#include "trackerTransform.h"
-#include "config_tform.h"
-
-TypeHandle TrackerTransform::_type_handle;
-
-TypeHandle TrackerTransform::_position_type;
-TypeHandle TrackerTransform::_pquat_type;
-
-TypeHandle TrackerTransform::_transform_type;
-
-////////////////////////////////////////////////////////////////////
-//     Function: TrackerTransform::Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-TrackerTransform::
-TrackerTransform(const string &name) :  DataNode(name) {
-  _transform = new MatrixDataAttribute;
-  _transform->set_value(LMatrix4f::ident_mat());
-  _transform_attrib.set_attribute(_transform_type, _transform);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TrackerTransform::transmit_data
-//       Access: Public
-//  Description: Constructs a transformation matrix from tracker data
-//               and passes it down the line
-////////////////////////////////////////////////////////////////////
-void TrackerTransform::
-transmit_data(NodeAttributes &data) {
-  const NodeAttribute *position = data.get_attribute(_position_type);
-  
-  if (tform_cat.is_debug()) {
-    tform_cat.debug() << "TrackerTransform:transmit_data" << endl;
-  }
-  if (position != (NodeAttribute *)NULL) {
-    LVecBase3f p = DCAST(Vec3DataAttribute, position)->get_value();
-    
-    LMatrix4f mat = LMatrix4f::translate_mat(p);
-    if (tform_cat.is_debug()) {
-      tform_cat.debug() << "Sending down " << mat << endl;
-    }
-    _transform->set_value(mat);
-  }
-
-  data = _transform_attrib;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TrackerTransform::init_type
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-void TrackerTransform::
-init_type() {
-  DataNode::init_type();
-  register_type(_type_handle, "TrackerTransform",
-		DataNode::get_class_type());
-
-  Vec3DataTransition::init_type();
-  Vec4DataTransition::init_type();
-  MatrixDataTransition::init_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(_transform_type, "Transform",
-			   MatrixDataTransition::get_class_type());
-}
-
-
-
-

+ 0 - 68
panda/src/tform/trackerTransform.h

@@ -1,68 +0,0 @@
-// Filename: trackerTransform.h
-// Created by:  jason (08Aug00)
-// 
-////////////////////////////////////////////////////////////////////
-
-#ifndef TRACKER_TRANSFORM_H
-#define TRACKER_TRANSFORM_H
-
-#include <pandabase.h>
-
-#include <dataNode.h>
-
-#include <doubleDataAttribute.h>
-#include <doubleDataTransition.h>
-#include <vec3DataAttribute.h>
-#include <vec3DataTransition.h>
-#include <vec3DataAttribute.h>
-#include <vec4DataTransition.h>
-#include <vec4DataAttribute.h>
-#include <matrixDataTransition.h>
-#include <matrixDataAttribute.h>
-#include <nodeAttributes.h>
-
-#include <luse.h>
-#include <lmatrix.h>
-
-
-////////////////////////////////////////////////////////////////////
-//       Class : TrackerTransform
-// Description : TrackerTransform reads the data send down the line
-//               by a TrackerNode and creates a transformation matrix
-//               from the data and sends that matrix down the line
-////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA TrackerTransform : public DataNode {
-PUBLISHED:
-  TrackerTransform(const string &name = "");
-
-public:
-  virtual void transmit_data(NodeAttributes &data);
-
-private:
-  NodeAttributes _transform_attrib;
-  PT(MatrixDataAttribute) _transform;
-
-  // inputs
-  static TypeHandle _position_type;
-  //NOTE!!!
-  //Currently not being factored into the matrix.  Needs to be done
-  static TypeHandle _pquat_type;
-
-  // outputs
-  static TypeHandle _transform_type;
-
-public:
-  virtual TypeHandle get_type() const {
-    return get_class_type();
-  }
-  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
-  static TypeHandle get_class_type() {
-    return _type_handle;
-  }
-  static void init_type();
-
-private:
-  static TypeHandle _type_handle;
-};
-
-#endif

+ 2 - 0
panda/src/vrpn/Sources.pp

@@ -16,6 +16,8 @@
     vrpnButton.I vrpnButton.cxx vrpnButton.h \
     vrpnButtonDevice.I vrpnButtonDevice.cxx vrpnButtonDevice.h \
     vrpnClient.h \
+    vrpnDial.I vrpnDial.cxx vrpnDial.h \
+    vrpnDialDevice.I vrpnDialDevice.cxx vrpnDialDevice.h \
     vrpnTracker.I vrpnTracker.cxx vrpnTracker.h \
     vrpnTrackerDevice.I vrpnTrackerDevice.cxx vrpnTrackerDevice.h \
     vrpn_interface.h

+ 2 - 0
panda/src/vrpn/config_vrpn.cxx

@@ -7,6 +7,7 @@
 #include "vrpnAnalogDevice.h"
 #include "vrpnButtonDevice.h"
 #include "vrpnClient.h"
+#include "vrpnDialDevice.h"
 #include "vrpnTrackerDevice.h"
 
 #include <dconfig.h>
@@ -19,5 +20,6 @@ ConfigureFn(config_vrpn) {
   VrpnAnalogDevice::init_type();
   VrpnButtonDevice::init_type();
   VrpnClient::init_type();
+  VrpnDialDevice::init_type();
   VrpnTrackerDevice::init_type();
 }

+ 118 - 1
panda/src/vrpn/vrpnClient.cxx

@@ -10,6 +10,8 @@
 #include "vrpnButtonDevice.h"
 #include "vrpnAnalog.h"
 #include "vrpnAnalogDevice.h"
+#include "vrpnDial.h"
+#include "vrpnDialDevice.h"
 #include "config_vrpn.h"
 
 #include <string_utils.h>
@@ -99,6 +101,16 @@ write(ostream &out, int indent_level) const {
       vrpn_analog->write(out, indent_level + 4);
     }
   }
+
+  if (!_dials.empty()) {
+    indent(out, indent_level + 2)
+      << _dials.size() << " dials:\n";
+    Dials::const_iterator di;
+    for (di = _dials.begin(); di != _dials.end(); ++di) {
+      VrpnDial *vrpn_dial = (*di).second;
+      vrpn_dial->write(out, indent_level + 4);
+    }
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -125,6 +137,9 @@ make_device(TypeHandle device_type, const string &device_name) {
   } else if (device_type == ClientAnalogDevice::get_class_type()) {
     return make_analog_device(device_name);
 
+  } else if (device_type == ClientDialDevice::get_class_type()) {
+    return make_dial_device(device_name);
+
   } else {
     return NULL;
   }
@@ -161,6 +176,9 @@ disconnect_device(TypeHandle device_type, const string &device_name,
     } else if (device->is_of_type(VrpnAnalogDevice::get_class_type())) {
       disconnect_analog_device(DCAST(VrpnAnalogDevice, device));
 
+    } else if (device->is_of_type(VrpnDialDevice::get_class_type())) {
+      disconnect_dial_device(DCAST(VrpnDialDevice, device));
+
     }
     return true;
   }
@@ -184,7 +202,7 @@ do_poll() {
   if (vrpn_cat.is_spam()) {
     vrpn_cat.spam()
       << "VrpnClient " << _server_name << " polling " 
-      << _trackers.size() + _buttons.size() + _analogs.size()
+      << _trackers.size() + _buttons.size() + _analogs.size() + _dials.size()
       << " devices.\n";
   }
 
@@ -205,6 +223,12 @@ do_poll() {
     VrpnAnalog *vrpn_analog = (*ai).second;
     vrpn_analog->poll();
   }
+
+  Dials::iterator di;
+  for (di = _dials.begin(); di != _dials.end(); ++di) {
+    VrpnDial *vrpn_dial = (*di).second;
+    vrpn_dial->poll();
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -345,6 +369,33 @@ make_analog_device(const string &device_name) {
   return device;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: VrpnClient::make_dial_device
+//       Access: Private
+//  Description: Creates a new dial device.  The device_name is sent
+//               verbatim to the VRPN library.
+////////////////////////////////////////////////////////////////////
+PT(ClientDevice) VrpnClient::
+make_dial_device(const string &device_name) {
+  if (vrpn_cat.is_debug()) {
+    vrpn_cat.debug()
+      << "Making dial device for " << device_name << "\n";
+  }
+
+  VrpnDial *dial = get_dial(device_name);
+
+  VrpnDialDevice *device = 
+    new VrpnDialDevice(this, device_name, dial);
+
+  if (vrpn_cat.is_debug()) {
+    vrpn_cat.debug()
+      << "Creating " << *device << "\n";
+  }
+
+  dial->mark(device);
+  return device;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: VrpnClient::disconnect_tracker_device
 //       Access: Private
@@ -390,6 +441,21 @@ disconnect_analog_device(VrpnAnalogDevice *device) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: VrpnClient::disconnect_dial_device
+//       Access: Private
+//  Description: Removes the dial device from the list of things to
+//               be updated.
+////////////////////////////////////////////////////////////////////
+void VrpnClient::
+disconnect_dial_device(VrpnDialDevice *device) {
+  VrpnDial *vrpn_dial = device->get_vrpn_dial();
+  vrpn_dial->unmark(device);
+  if (vrpn_dial->is_empty()) {
+    free_dial(vrpn_dial);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: VrpnClient::get_tracker
 //       Access: Private
@@ -543,6 +609,57 @@ free_analog(VrpnAnalog *vrpn_analog) {
   delete vrpn_analog;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: VrpnClient::get_dial
+//       Access: Private
+//  Description: Finds a VrpnDial of the indicated name, and
+//               returns it if one already exists, or creates a new
+//               one if it does not.
+////////////////////////////////////////////////////////////////////
+VrpnDial *VrpnClient::
+get_dial(const string &dial_name) {
+  Dials::iterator di;
+  di = _dials.find(dial_name);
+
+  if (di != _dials.end()) {
+    return (*di).second;
+  }
+
+  VrpnDial *vrpn_dial = new VrpnDial(dial_name, _connection);
+  _dials.insert(Dials::value_type(dial_name, vrpn_dial));
+
+  if (vrpn_cat.is_debug()) {
+    vrpn_cat.debug()
+      << "Creating dial " << *vrpn_dial << "\n";
+  }
+
+  return vrpn_dial;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VrpnClient::free_dial
+//       Access: Private
+//  Description: Removes and deletes the indicated VrpnDial, which
+//               is no longer referenced by any VrpnDialDevices.
+////////////////////////////////////////////////////////////////////
+void VrpnClient::
+free_dial(VrpnDial *vrpn_dial) {
+  nassertv(vrpn_dial->is_empty());
+
+  if (vrpn_cat.is_debug()) {
+    vrpn_cat.debug()
+      << "Deleting dial " << *vrpn_dial << "\n";
+  }
+
+  Dials::iterator di;
+  di = _dials.find(vrpn_dial->get_dial_name());
+  nassertv(di != _dials.end());
+  nassertv((*di).second == vrpn_dial);
+
+  _dials.erase(di);
+  delete vrpn_dial;
+}
+
 
 #if 0
 

+ 9 - 0
panda/src/vrpn/vrpnClient.h

@@ -17,6 +17,8 @@ class VrpnButton;
 class VrpnButtonDevice;
 class VrpnAnalog;
 class VrpnAnalogDevice;
+class VrpnDial;
+class VrpnDialDevice;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : VrpnClient
@@ -52,9 +54,11 @@ private:
   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);
+  PT(ClientDevice) make_dial_device(const string &device_name);
   void disconnect_tracker_device(VrpnTrackerDevice *device);
   void disconnect_button_device(VrpnButtonDevice *device);
   void disconnect_analog_device(VrpnAnalogDevice *device);
+  void disconnect_dial_device(VrpnDialDevice *device);
 
   VrpnTracker *get_tracker(const string &tracker_name);
   void free_tracker(VrpnTracker *vrpn_tracker);
@@ -65,6 +69,9 @@ private:
   VrpnAnalog *get_analog(const string &analog_name);
   void free_analog(VrpnAnalog *vrpn_analog);
 
+  VrpnDial *get_dial(const string &dial_name);
+  void free_dial(VrpnDial *vrpn_dial);
+
 private:
   string _server_name;
   vrpn_Connection *_connection;
@@ -72,10 +79,12 @@ private:
   typedef map<string, VrpnTracker *> Trackers;
   typedef map<string, VrpnButton *> Buttons;
   typedef map<string, VrpnAnalog *> Analogs;
+  typedef map<string, VrpnDial *> Dials;
 
   Trackers _trackers;
   Buttons _buttons;
   Analogs _analogs;
+  Dials _dials;
 
 
 public:

+ 38 - 0
panda/src/vrpn/vrpnDial.I

@@ -0,0 +1,38 @@
+// Filename: vrpnDial.I
+// Created by:  drose (26Jan01)
+// 
+////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////
+//     Function: VrpnDial::get_dial_name
+//       Access: Public
+//  Description: Returns the name of the dial device that was used
+//               to create this VrpnDial.
+////////////////////////////////////////////////////////////////////
+INLINE const string &VrpnDial::
+get_dial_name() const {
+  return _dial_name;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VrpnDial::is_empty
+//       Access: Public
+//  Description: Returns true if no VrpnDialDevices reference this
+//               VrpnDial, or false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool VrpnDial::
+is_empty() const {
+  return _devices.empty();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VrpnDial::poll
+//       Access: Public
+//  Description: Polls the connected device.  Normally you should not
+//               call this directly; this will be called by the
+//               VrpnClient.
+////////////////////////////////////////////////////////////////////
+INLINE void VrpnDial::
+poll() {
+  _dial->mainloop();
+}

+ 118 - 0
panda/src/vrpn/vrpnDial.cxx

@@ -0,0 +1,118 @@
+// Filename: vrpnDial.cxx
+// Created by:  drose (26Jan01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "vrpnDial.h"
+#include "vrpnDialDevice.h"
+#include "vrpnClient.h"
+#include "config_vrpn.h"
+
+#include <indent.h>
+
+#include <algorithm>
+
+////////////////////////////////////////////////////////////////////
+//     Function: VrpnDial::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+VrpnDial::
+VrpnDial(const string &dial_name, vrpn_Connection *connection) :
+  _dial_name(dial_name)
+{
+  _dial = new vrpn_Dial_Remote(_dial_name.c_str(), connection);
+
+  _dial->register_change_handler((void*)this, &vrpn_dial_callback);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VrpnDial::Destructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+VrpnDial::
+~VrpnDial() {
+  delete _dial;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VrpnDial::mark
+//       Access: Public
+//  Description: Adds the indicated VrpnDialDevice to the list of
+//               devices that are sharing this VrpnDial.
+////////////////////////////////////////////////////////////////////
+void VrpnDial::
+mark(VrpnDialDevice *device) {
+  if (vrpn_cat.is_debug()) {
+    vrpn_cat.debug() << *this << " marking " << *device << "\n";
+  }
+  _devices.push_back(device);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VrpnDial::unmark
+//       Access: Public
+//  Description: Removes the indicated VrpnDialDevice from the list
+//               of devices that are sharing this VrpnDial.
+////////////////////////////////////////////////////////////////////
+void VrpnDial::
+unmark(VrpnDialDevice *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: VrpnDial::output
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void VrpnDial::
+output(ostream &out) const {
+  out << _dial_name;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VrpnDial::write
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void VrpnDial::
+write(ostream &out, int indent_level) const {
+  indent(out, indent_level) 
+    << get_dial_name() << " ("
+    << _devices.size() << " devices)\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VrpnDial::vrpn_dial_callback
+//       Access: Private, Static
+//  Description: Receives the dial event data from the VRPN
+//               code and sends it to any interested
+//               VrpnDialDevices.
+////////////////////////////////////////////////////////////////////
+void VrpnDial::
+vrpn_dial_callback(void *userdata, const vrpn_DIALCB info) {
+  VrpnDial *self = (VrpnDial *)userdata;
+
+  if (vrpn_cat.is_debug()) {
+    vrpn_cat.debug()
+      << *self << " got dial " << info.dial << " = " << info.change << "\n";
+  }
+
+  Devices::iterator di;
+  for (di = self->_devices.begin(); di != self->_devices.end(); ++di) {
+    VrpnDialDevice *device = (*di);
+    device->lock();
+    device->push_dial(info.dial, info.change);
+    device->unlock();
+  }
+}

+ 68 - 0
panda/src/vrpn/vrpnDial.h

@@ -0,0 +1,68 @@
+// Filename: vrpnDial.h
+// Created by:  drose (26Jan01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef VRPNDIAL_H
+#define VRPNDIAL_H
+
+#include <pandabase.h>
+
+#include "vrpn_interface.h"
+
+#include <vector>
+
+class VrpnDialDevice;
+
+////////////////////////////////////////////////////////////////////
+//       Class : VrpnDial
+// Description : This is the actual interface to a particular VRPN
+//               dial device, and all of its numbered dials.  A
+//               pointer to this object is stored in the VrpnClient
+//               class for each differently-named VRPN dial device
+//               we connect to.
+//
+//               The VRPN callbacks go here, which in turn get
+//               vectored out to any VrpnDialDevice objects that
+//               register with this.  When the last VrpnDialDevice
+//               object unregisters, the VrpnDial will be deleted
+//               by the VrpnClient.
+//
+//               This class does not need to be exported from the DLL.
+////////////////////////////////////////////////////////////////////
+class VrpnDial {
+public:
+  VrpnDial(const string &dial_name, vrpn_Connection *connection);
+  ~VrpnDial();
+
+  INLINE const string &get_dial_name() const;
+  INLINE bool is_empty() const;
+
+  void mark(VrpnDialDevice *device);
+  void unmark(VrpnDialDevice *device);
+
+  INLINE void poll();
+
+  void output(ostream &out) const;
+  void write(ostream &out, int indent_level = 0) const;
+
+private:
+  static void
+  vrpn_dial_callback(void *userdata, const vrpn_DIALCB info);
+
+private:
+  string _dial_name;
+  vrpn_Dial_Remote *_dial;
+
+  typedef vector<VrpnDialDevice *> Devices;
+  Devices _devices;
+};
+
+INLINE ostream &operator << (ostream &out, const VrpnDial &dial) {
+  dial.output(out);
+  return out;
+}
+
+#include "vrpnDial.I"
+
+#endif

+ 17 - 0
panda/src/vrpn/vrpnDialDevice.I

@@ -0,0 +1,17 @@
+// Filename: vrpnDialDevice.I
+// Created by:  drose (26Jan01)
+// 
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: VrpnDialDevice::get_vrpn_dial
+//       Access: Public
+//  Description: Returns a pointer to the particular VrpnDial this
+//               device gets its data from.  This pointer may be
+//               shared with other VrpnDialDevice objects.
+////////////////////////////////////////////////////////////////////
+INLINE VrpnDial *VrpnDialDevice::
+get_vrpn_dial() const {
+  return _vrpn_dial;
+}

+ 32 - 0
panda/src/vrpn/vrpnDialDevice.cxx

@@ -0,0 +1,32 @@
+// Filename: vrpnDialDevice.cxx
+// Created by:  drose (26Jan01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "vrpnDialDevice.h"
+#include "vrpnClient.h"
+
+TypeHandle VrpnDialDevice::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: VrpnDialDevice::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+VrpnDialDevice::
+VrpnDialDevice(VrpnClient *client, const string &device_name,
+		 VrpnDial *vrpn_dial) :
+  ClientDialDevice(client, device_name),
+  _vrpn_dial(vrpn_dial)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VrpnDialDevice::Destructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+VrpnDialDevice::
+~VrpnDialDevice() {
+  disconnect();
+}

+ 57 - 0
panda/src/vrpn/vrpnDialDevice.h

@@ -0,0 +1,57 @@
+// Filename: vrpnDialDevice.h
+// Created by:  drose (26Jan01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef VRPNDIALDEVICE_H
+#define VRPNDIALDEVICE_H
+
+#include <pandabase.h>
+
+#include <clientDialDevice.h>
+
+class VrpnClient;
+class VrpnDial;
+
+////////////////////////////////////////////////////////////////////
+//       Class : VrpnDialDevice
+// Description : The Panda interface to a VRPN dial device.  This
+//               object will be returned by VrpnClient::make_device(),
+//               for attaching to a DialNode.
+//
+//               This class does not need to be exported from the DLL.
+////////////////////////////////////////////////////////////////////
+class VrpnDialDevice : public ClientDialDevice {
+public:
+  VrpnDialDevice(VrpnClient *client, const string &device_name,
+		   VrpnDial *vrpn_dial);
+  virtual ~VrpnDialDevice();
+
+  INLINE VrpnDial *get_vrpn_dial() const;
+
+private:
+  VrpnDial *_vrpn_dial;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    ClientDialDevice::init_type();
+    register_type(_type_handle, "VrpnDialDevice",
+                  ClientDialDevice::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 VrpnDial;
+};
+
+#include "vrpnDialDevice.I"
+
+#endif