Browse Source

move setSmPos() etc. into C++

David Rose 21 years ago
parent
commit
157b9feb5f

+ 3 - 5
direct/src/distributed/DistributedSmoothNode.py

@@ -85,6 +85,7 @@ class DistributedSmoothNode(DistributedNode.DistributedNode,
             self.DistributedSmoothNode_initialized = 1
             DistributedNode.DistributedNode.__init__(self, cr)
             DistributedSmoothNodeBase.DistributedSmoothNodeBase.__init__(self)
+            self.cnode.setRepository(cr, 0, 0)
 
             self.smoother = SmoothMover()
             self.smoothStarted = 0
@@ -308,11 +309,8 @@ class DistributedSmoothNode(DistributedNode.DistributedNode,
         DistributedNode.DistributedNode.d_setParent(self, parentToken)
 
         self.forceToTruePosition()
-        xyz = self.getPos()
-        hpr = self.getHpr()
-        x=xyz[0]; y=xyz[1]; z=xyz[2]
-        h=hpr[0]; p=hpr[1]; r=hpr[2]
-        self.d_setSmPosHpr(x,y,z,h,p,r)
+        self.cnode.initialize(self, self.dclass, self.doId)
+        self.cnode.sendEverything()
 
     ### Monitor clock sync ###
 

+ 2 - 0
direct/src/distributed/DistributedSmoothNodeAI.py

@@ -9,6 +9,8 @@ class DistributedSmoothNodeAI(DistributedNodeAI.DistributedNodeAI,
         DistributedNodeAI.DistributedNodeAI.__init__(self, air, name)
         DistributedSmoothNodeBase.DistributedSmoothNodeBase.__init__(self)
 
+        self.cnode.setRepository(air, 1, air.ourChannel)
+
     def delete(self):
         DistributedSmoothNodeBase.DistributedSmoothNodeBase.delete(self)
         DistributedNodeAI.DistributedNodeAI.delete(self)

+ 11 - 178
direct/src/distributed/DistributedSmoothNodeBase.py

@@ -10,46 +10,13 @@ class DistributedSmoothNodeBase:
     BroadcastTypes = Enum('FULL, XYH')
     
     def __init__(self):
-        pass
+        self.cnode = CDistributedSmoothNodeBase()
+        self.cnode.setClockDelta(globalClockDelta)
 
     def delete(self):
         # make sure our task is gone
         self.stopPosHprBroadcast()
 
-    ### distributed set pos and hpr functions ###
-
-    ### These functions send the distributed update to set the
-    ### appropriate values on the remote side.  These are
-    ### composite fields, with all the likely combinations
-    ### defined; each function maps (via the dc file) to one or
-    ### more component operations on the remote client.
-
-    def d_setSmStop(self):
-        self.sendUpdate("setSmStop", [globalClockDelta.getFrameNetworkTime()])
-    def d_setSmH(self, h):
-        self.sendUpdate("setSmH", [h, globalClockDelta.getFrameNetworkTime()])
-    def d_setSmXY(self, x, y):
-        self.sendUpdate("setSmXY", [x, y,
-                                    globalClockDelta.getFrameNetworkTime()])
-    def d_setSmXZ(self, x, z):
-        self.sendUpdate("setSmXZ", [x, z,
-                                    globalClockDelta.getFrameNetworkTime()])
-    def d_setSmPos(self, x, y, z):
-        self.sendUpdate("setSmPos", [x, y, z,
-                                     globalClockDelta.getFrameNetworkTime()])
-    def d_setSmHpr(self, h, p, r):
-        self.sendUpdate("setSmHpr", [h, p, r,
-                                     globalClockDelta.getFrameNetworkTime()])
-    def d_setSmXYH(self, x, y, h):
-        self.sendUpdate("setSmXYH", [x, y, h,
-                                     globalClockDelta.getFrameNetworkTime()])
-    def d_setSmXYZH(self, x, y, z, h):
-        self.sendUpdate("setSmXYZH", [x, y, z, h,
-                                      globalClockDelta.getFrameNetworkTime()])
-    def d_setSmPosHpr(self, x, y, z, h, p, r):
-        self.sendUpdate("setSmPosHpr", [x, y, z, h, p, r,
-                                        globalClockDelta.getFrameNetworkTime()])
-
     def b_clearSmoothing(self):
         self.d_clearSmoothing()
         self.clearSmoothing()
@@ -68,6 +35,9 @@ class DistributedSmoothNodeBase:
         self.d_broadcastPosHpr = None
 
     def startPosHprBroadcast(self, period=.2, stagger=0, type=None):
+        if self.cnode == None:
+            self.initializeCnode()
+        
         BT = DistributedSmoothNodeBase.BroadcastTypes
         if type is None:
             type = BT.FULL
@@ -75,8 +45,8 @@ class DistributedSmoothNodeBase:
         self.broadcastType = type
 
         broadcastFuncs = {
-            BT.FULL: self.d_broadcastPosHpr_FULL,
-            BT.XYH:  self.d_broadcastPosHpr_XYH,
+            BT.FULL: self.cnode.broadcastPosHprFull,
+            BT.XYH:  self.cnode.broadcastPosHprXyh,
             }
         self.d_broadcastPosHpr = broadcastFuncs[self.broadcastType]
         
@@ -84,23 +54,15 @@ class DistributedSmoothNodeBase:
         # over 'period' seconds, to spread out task processing over time
         # when a large number of SmoothNodes are created simultaneously.
         taskName = self.getPosHprBroadcastTaskName()
+
         # Set up telemetry optimization variables
-        xyz = self.getPos()
-        hpr = self.getHpr()
+        self.cnode.initialize(self, self.dclass, self.doId)
 
-        self.__storeX = xyz[0]
-        self.__storeY = xyz[1]
-        self.__storeZ = xyz[2]
-        self.__storeH = hpr[0]
-        self.__storeP = hpr[1]
-        self.__storeR = hpr[2]
-        self.__storeStop = 0
-        self.__epsilon = 0.01
         self.__broadcastPeriod = period
         # Broadcast our initial position
         self.b_clearSmoothing()
-        self.d_setSmPosHpr(self.__storeX, self.__storeY, self.__storeZ,
-                           self.__storeH, self.__storeP, self.__storeR)
+        self.cnode.sendEverything()
+
         # remove any old tasks
         taskMgr.remove(taskName)
         # spawn the new task
@@ -119,132 +81,3 @@ class DistributedSmoothNodeBase:
         taskMgr.doMethodLater(self.__broadcastPeriod,
                               self.__posHprBroadcast, taskName)
         return Task.done
-
-    def d_broadcastPosHpr_FULL(self):
-        # send out the minimal bits to describe our new position
-        xyz = self.getPos()
-        hpr = self.getHpr()
-
-        if abs(self.__storeX - xyz[0]) > self.__epsilon:
-            self.__storeX = xyz[0]
-            newX = 1
-        else:
-            newX = 0
-
-        if abs(self.__storeY - xyz[1]) > self.__epsilon:
-            self.__storeY = xyz[1]
-            newY = 1
-        else:
-            newY = 0
-
-        if abs(self.__storeZ - xyz[2]) > self.__epsilon:
-            self.__storeZ = xyz[2]
-            newZ = 1
-        else:
-            newZ = 0
-
-        if abs(self.__storeH - hpr[0]) > self.__epsilon:
-            self.__storeH = hpr[0]
-            newH = 1
-        else:
-            newH = 0
-
-        if abs(self.__storeP - hpr[1]) > self.__epsilon:
-            self.__storeP = hpr[1]
-            newP = 1
-        else:
-            newP = 0
-
-        if abs(self.__storeR - hpr[2]) > self.__epsilon:
-            self.__storeR = hpr[2]
-            newR = 1
-        else:
-            newR = 0
-
-        # Check for changes:
-        if not(newX or newY or newZ or newH or newP or newR):
-            # No change
-            # Send one and only one "stop" message.
-            if not self.__storeStop:
-                self.__storeStop = 1
-                self.d_setSmStop()
-            # print 'no change'
-        elif (newH) and not(newX or newY or newZ or newP or newR):
-            # Only change in H
-            self.__storeStop = 0
-            self.d_setSmH(self.__storeH)
-            # print ("H change")
-        elif (newX or newY) and not(newZ or newH or newP or newR):
-            # Only change in X, Y
-            self.__storeStop = 0
-            self.d_setSmXY(self.__storeX, self.__storeY)
-            # print ("XY change")
-        elif (newX or newY or newZ) and not(newH or newP or newR):
-            # Only change in X, Y, Z
-            self.__storeStop = 0
-            self.d_setSmPos(self.__storeX, self.__storeY, self.__storeZ)
-            # print ("XYZ change")
-        elif (newX or newY or newH) and not(newZ or newP or newR):
-            # Only change in X, Y, H
-            self.__storeStop = 0
-            self.d_setSmXYH(self.__storeX, self.__storeY, self.__storeH)
-            # print ("XYH change")
-        elif (newX or newY or newZ or newH) and not(newP or newR):
-            # Only change in X, Y, Z, H
-            self.__storeStop = 0
-            self.d_setSmXYZH(self.__storeX, self.__storeY, self.__storeZ, self.__storeH)
-            # print ("XYZH change")
-        else:
-            # Other changes
-            self.__storeStop = 0
-            self.d_setSmPosHpr(self.__storeX, self.__storeY, self.__storeZ,
-                               self.__storeH, self.__storeP, self.__storeR)
-            # print ("XYZHPR change")
-
-    def d_broadcastPosHpr_XYH(self):
-        # send out the minimal bits to describe our new position
-        assert not self.isEmpty(), 'DistributedSmoothNode %s has been removed from graph?' % self.doId
-        xyz = self.getPos()
-        h   = self.getH()
-
-        if abs(self.__storeX - xyz[0]) > self.__epsilon:
-            self.__storeX = xyz[0]
-            newX = 1
-        else:
-            newX = 0
-
-        if abs(self.__storeY - xyz[1]) > self.__epsilon:
-            self.__storeY = xyz[1]
-            newY = 1
-        else:
-            newY = 0
-
-        if abs(self.__storeH - h) > self.__epsilon:
-            self.__storeH = h
-            newH = 1
-        else:
-            newH = 0
-
-        # Check for changes:
-        if not(newX or newY or newH):
-            # No change
-            # Send one and only one "stop" message.
-            if not self.__storeStop:
-                self.__storeStop = 1
-                self.d_setSmStop()
-            # print 'no change'
-        elif (newH) and not(newX or newY):
-            # Only change in H
-            self.__storeStop = 0
-            self.d_setSmH(self.__storeH)
-            # print ("H change")
-        elif (newX or newY) and not(newH):
-            # Only change in X, Y
-            self.__storeStop = 0
-            self.d_setSmXY(self.__storeX, self.__storeY)
-            # print ("XY change")
-        else:
-            # Only change in X, Y, H
-            self.__storeStop = 0
-            self.d_setSmXYH(self.__storeX, self.__storeY, self.__storeH)
-            # print ("XYH change")

+ 3 - 1
direct/src/distributed/Sources.pp

@@ -18,7 +18,9 @@
   #define SOURCES \
     config_distributed.cxx config_distributed.h \
     cConnectionRepository.cxx cConnectionRepository.I \
-    cConnectionRepository.h
+    cConnectionRepository.h \
+    cDistributedSmoothNodeBase.cxx cDistributedSmoothNodeBase.I \
+    cDistributedSmoothNodeBase.h
 
   #define IGATESCAN all
 #end lib_target

+ 188 - 0
direct/src/distributed/cDistributedSmoothNodeBase.I

@@ -0,0 +1,188 @@
+// Filename: cDistributedSmoothNodeBase.I
+// Created by:  drose (03Sep04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: CDistributedSmoothNodeBase::set_repository
+//       Access: Published, Static
+//  Description: Tells the C++ class definition about the AI or Client
+//               repository, used for sending datagrams.
+////////////////////////////////////////////////////////////////////
+INLINE void CDistributedSmoothNodeBase::
+set_repository(CConnectionRepository *repository,
+               bool is_ai, CHANNEL_TYPE ai_id) {
+  _repository = repository;
+  _is_ai = is_ai;
+  _ai_id = ai_id;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CDistributedSmoothNodeBase::set_clock_delta
+//       Access: Published, Static
+//  Description: Tells the C++ class definition about the global
+//               ClockDelta object.
+////////////////////////////////////////////////////////////////////
+INLINE void CDistributedSmoothNodeBase::
+set_clock_delta(PyObject *clock_delta) {
+  _clock_delta = clock_delta;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CDistributedSmoothNodeBase::only_changed
+//       Access: Private, Static
+//  Description: Returns true if at least some of the bits of compare
+//               are set in flags, but no bits outside of compare are
+//               set.  That is to say, that the only things that are
+//               changed are the bits indicated in compare.
+////////////////////////////////////////////////////////////////////
+INLINE bool CDistributedSmoothNodeBase::
+only_changed(int flags, int compare) {
+  return (flags & compare) != 0 && (flags & ~compare) == 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CDistributedSmoothNodeBase::d_setSmStop
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void CDistributedSmoothNodeBase::
+d_setSmStop() {
+  DCPacker packer;
+  begin_send_update(packer, "setSmStop");
+  finish_send_update(packer);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CDistributedSmoothNodeBase::d_setSmH
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void CDistributedSmoothNodeBase::
+d_setSmH(float h) {
+  DCPacker packer;
+  begin_send_update(packer, "setSmH");
+  packer.pack_double(h);
+  finish_send_update(packer);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CDistributedSmoothNodeBase::d_setSmXY
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void CDistributedSmoothNodeBase::
+d_setSmXY(float x, float y) {
+  DCPacker packer;
+  begin_send_update(packer, "setSmXY");
+  packer.pack_double(x);
+  packer.pack_double(y);
+  finish_send_update(packer);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CDistributedSmoothNodeBase::d_setSmXZ
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void CDistributedSmoothNodeBase::
+d_setSmXZ(float x, float z) {
+  DCPacker packer;
+  begin_send_update(packer, "setSmXZ");
+  packer.pack_double(x);
+  packer.pack_double(z);
+  finish_send_update(packer);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CDistributedSmoothNodeBase::d_setSmPos
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void CDistributedSmoothNodeBase::
+d_setSmPos(float x, float y, float z) {
+  DCPacker packer;
+  begin_send_update(packer, "setSmPos");
+  packer.pack_double(x);
+  packer.pack_double(y);
+  packer.pack_double(z);
+  finish_send_update(packer);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CDistributedSmoothNodeBase::d_setSmHpr
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void CDistributedSmoothNodeBase::
+d_setSmHpr(float h, float p, float r) {
+  DCPacker packer;
+  begin_send_update(packer, "setSmHpr");
+  packer.pack_double(h);
+  packer.pack_double(p);
+  packer.pack_double(r);
+  finish_send_update(packer);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CDistributedSmoothNodeBase::d_setSmXYH
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void CDistributedSmoothNodeBase::
+d_setSmXYH(float x, float y, float h) {
+  DCPacker packer;
+  begin_send_update(packer, "setSmXYH");
+  packer.pack_double(x);
+  packer.pack_double(y);
+  packer.pack_double(h);
+  finish_send_update(packer);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CDistributedSmoothNodeBase::d_setSmXYZH
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void CDistributedSmoothNodeBase::
+d_setSmXYZH(float x, float y, float z, float h) {
+  DCPacker packer;
+  begin_send_update(packer, "setSmXYZH");
+  packer.pack_double(x);
+  packer.pack_double(y);
+  packer.pack_double(z);
+  packer.pack_double(h);
+  finish_send_update(packer);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CDistributedSmoothNodeBase::d_setSmPosHpr
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void CDistributedSmoothNodeBase::
+d_setSmPosHpr(float x, float y, float z, float h, float p, float r) {
+  DCPacker packer;
+  begin_send_update(packer, "setSmPosHpr");
+  packer.pack_double(x);
+  packer.pack_double(y);
+  packer.pack_double(z);
+  packer.pack_double(h);
+  packer.pack_double(p);
+  packer.pack_double(r);
+  finish_send_update(packer);
+}

+ 284 - 0
direct/src/distributed/cDistributedSmoothNodeBase.cxx

@@ -0,0 +1,284 @@
+// Filename: cDistributedSmoothNodeBase.cxx
+// Created by:  drose (03Sep04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "cDistributedSmoothNodeBase.h"
+#include "cConnectionRepository.h"
+#include "dcField.h"
+#include "dcClass.h"
+#include "dcmsgtypes.h"
+
+static const float smooth_node_epsilon = 0.01;
+static const double network_time_precision = 100.0;  // Matches ClockDelta.py
+
+CConnectionRepository *CDistributedSmoothNodeBase::_repository = NULL;
+bool CDistributedSmoothNodeBase::_is_ai;
+CHANNEL_TYPE CDistributedSmoothNodeBase::_ai_id;
+PyObject *CDistributedSmoothNodeBase::_clock_delta = NULL;
+
+////////////////////////////////////////////////////////////////////
+//     Function: CDistributedSmoothNodeBase::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+CDistributedSmoothNodeBase::
+CDistributedSmoothNodeBase() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CDistributedSmoothNodeBase::Destructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+CDistributedSmoothNodeBase::
+~CDistributedSmoothNodeBase() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CDistributedSmoothNodeBase::initialize
+//       Access: Published
+//  Description: Initializes the internal structures from some
+//               constructs that are normally stored only in Python.
+//               Also reads the current node's pos & hpr values in
+//               preparation for transmitting them via one of the
+//               broadcast_pos_hpr_*() methods.
+////////////////////////////////////////////////////////////////////
+void CDistributedSmoothNodeBase::
+initialize(const NodePath &node_path, DCClass *dclass, CHANNEL_TYPE do_id) {
+  _node_path = node_path;
+  _dclass = dclass;
+  _do_id = do_id;
+
+  nassertv(!_node_path.is_empty());
+
+  _store_xyz = _node_path.get_pos();
+  _store_hpr = _node_path.get_hpr();
+  _store_stop = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CDistributedSmoothNodeBase::send_everything
+//       Access: Published
+//  Description: Broadcasts the current pos/hpr in its complete form.
+////////////////////////////////////////////////////////////////////
+void CDistributedSmoothNodeBase::
+send_everything() {
+  d_setSmPosHpr(_store_xyz[0], _store_xyz[1], _store_xyz[2], 
+                _store_hpr[0], _store_hpr[1], _store_hpr[2]);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CDistributedSmoothNodeBase::broadcast_pos_hpr_full
+//       Access: Published
+//  Description: Examines the complete pos/hpr information to see
+//               which of the six elements have changed, and
+//               broadcasts the appropriate messages.
+////////////////////////////////////////////////////////////////////
+void CDistributedSmoothNodeBase::
+broadcast_pos_hpr_full() {
+  LPoint3f xyz = _node_path.get_pos();
+  LVecBase3f hpr = _node_path.get_hpr();
+
+  int flags = 0;
+
+  if (!IS_THRESHOLD_EQUAL(_store_xyz[0], xyz[0], smooth_node_epsilon)) {
+    _store_xyz[0] = xyz[0];
+    flags |= F_new_x;
+  }
+
+  if (!IS_THRESHOLD_EQUAL(_store_xyz[1], xyz[1], smooth_node_epsilon)) {
+    _store_xyz[1] = xyz[1];
+    flags |= F_new_y;
+  }
+
+  if (!IS_THRESHOLD_EQUAL(_store_xyz[2], xyz[2], smooth_node_epsilon)) {
+    _store_xyz[2] = xyz[2];
+    flags |= F_new_z;
+  }
+
+  if (!IS_THRESHOLD_EQUAL(_store_hpr[0], hpr[0], smooth_node_epsilon)) {
+    _store_hpr[0] = hpr[0];
+    flags |= F_new_h;
+  }
+
+  if (!IS_THRESHOLD_EQUAL(_store_hpr[1], hpr[1], smooth_node_epsilon)) {
+    _store_hpr[1] = hpr[1];
+    flags |= F_new_p;
+  }
+
+  if (!IS_THRESHOLD_EQUAL(_store_hpr[2], hpr[2], smooth_node_epsilon)) {
+    _store_hpr[2] = hpr[2];
+    flags |= F_new_r;
+  }
+
+  if (flags == 0) {
+    // No change.  Send one and only one "stop" message.
+    if (!_store_stop) {
+      _store_stop = true;
+      d_setSmStop();
+    }
+
+  } else if (only_changed(flags, F_new_h)) {
+    // Only change in H.
+    _store_stop = false;
+    d_setSmH(_store_hpr[0]);
+
+  } else if (only_changed(flags, F_new_x | F_new_y)) {
+    // Only change in X, Y
+    _store_stop = false;
+    d_setSmXY(_store_xyz[0], _store_xyz[1]);
+
+  } else if (only_changed(flags, F_new_x | F_new_z)) {
+    // Only change in X, Z
+    _store_stop = false;
+    d_setSmXZ(_store_xyz[0], _store_xyz[2]);
+
+  } else if (only_changed(flags, F_new_x | F_new_y | F_new_z)) {
+    // Only change in X, Y, Z
+    _store_stop = false;
+    d_setSmPos(_store_xyz[0], _store_xyz[1], _store_xyz[2]);
+
+  } else if (only_changed(flags, F_new_h | F_new_p | F_new_r)) {
+    // Only change in H, P, R
+    _store_stop = false;
+    d_setSmHpr(_store_hpr[0], _store_hpr[1], _store_hpr[2]);
+
+  } else if (only_changed(flags, F_new_x | F_new_y | F_new_h)) {
+    // Only change in X, Y, H
+    _store_stop = false;
+    d_setSmXYH(_store_xyz[0], _store_xyz[1], _store_hpr[0]);
+
+  } else if (only_changed(flags, F_new_x | F_new_y | F_new_z | F_new_h)) {
+    // Only change in X, Y, Z, H
+    _store_stop = false;
+    d_setSmXYZH(_store_xyz[0], _store_xyz[1], _store_xyz[2], _store_hpr[0]);
+
+  } else {
+    // Any other change
+    _store_stop = false;
+    d_setSmPosHpr(_store_xyz[0], _store_xyz[1], _store_xyz[2], 
+                  _store_hpr[0], _store_hpr[1], _store_hpr[2]);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CDistributedSmoothNodeBase::broadcast_pos_hpr_xyh
+//       Access: Published
+//  Description: Examines only X, Y, and H of the pos/hpr information,
+//               and broadcasts the appropriate messages.
+////////////////////////////////////////////////////////////////////
+void CDistributedSmoothNodeBase::
+broadcast_pos_hpr_xyh() {
+  LPoint3f xyz = _node_path.get_pos();
+  LVecBase3f hpr = _node_path.get_hpr();
+
+  int flags = 0;
+
+  if (!IS_THRESHOLD_EQUAL(_store_xyz[0], xyz[0], smooth_node_epsilon)) {
+    _store_xyz[0] = xyz[0];
+    flags |= F_new_x;
+  }
+
+  if (!IS_THRESHOLD_EQUAL(_store_xyz[1], xyz[1], smooth_node_epsilon)) {
+    _store_xyz[1] = xyz[1];
+    flags |= F_new_y;
+  }
+
+  if (!IS_THRESHOLD_EQUAL(_store_hpr[0], hpr[0], smooth_node_epsilon)) {
+    _store_hpr[0] = hpr[0];
+    flags |= F_new_h;
+  }
+
+  if (flags == 0) {
+    // No change.  Send one and only one "stop" message.
+    if (!_store_stop) {
+      _store_stop = true;
+      d_setSmStop();
+    }
+
+  } else if (only_changed(flags, F_new_h)) {
+    // Only change in H.
+    _store_stop = false;
+    d_setSmH(_store_hpr[0]);
+
+  } else if (only_changed(flags, F_new_x | F_new_y)) {
+    // Only change in X, Y
+    _store_stop = false;
+    d_setSmXY(_store_xyz[0], _store_xyz[1]);
+
+  } else {
+    // Any other change.
+    _store_stop = false;
+    d_setSmXYH(_store_xyz[0], _store_xyz[1], _store_hpr[0]);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CDistributedSmoothNodeBase::begin_send_update
+//       Access: Private
+//  Description: Fills up the packer with the data appropriate for
+//               sending an update on the indicated field name, up
+//               until the arguments.
+////////////////////////////////////////////////////////////////////
+void CDistributedSmoothNodeBase::
+begin_send_update(DCPacker &packer, const string &field_name) {
+  DCField *field = _dclass->get_field_by_name(field_name);
+  nassertv(field != (DCField *)NULL);
+
+  if (_is_ai) {
+    packer.RAW_PACK_CHANNEL(_do_id);
+    packer.RAW_PACK_CHANNEL(_ai_id);
+    packer.raw_pack_uint8('A');
+    packer.raw_pack_uint16(STATESERVER_OBJECT_UPDATE_FIELD);
+    packer.raw_pack_uint32(_do_id);
+    packer.raw_pack_uint16(field->get_number());
+
+  } else {
+    packer.raw_pack_uint16(CLIENT_OBJECT_UPDATE_FIELD);
+    packer.raw_pack_uint32(_do_id);
+    packer.raw_pack_uint16(field->get_number());
+  }
+
+  packer.begin_pack(field);
+  packer.push();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CDistributedSmoothNodeBase::finish_send_update
+//       Access: Private
+//  Description: Appends the timestamp and sends the update.
+////////////////////////////////////////////////////////////////////
+void CDistributedSmoothNodeBase::
+finish_send_update(DCPacker &packer) {
+  PyObject *clock_delta = PyObject_GetAttrString(_clock_delta, "delta");
+  nassertv(clock_delta != NULL);
+  double delta = PyFloat_AsDouble(clock_delta);
+  Py_DECREF(clock_delta);
+
+  double local_time = ClockObject::get_global_clock()->get_frame_time();
+
+  short network_time = (short)(int)cfloor(((local_time - delta) * network_time_precision) + 0.5);
+  packer.pack_int(network_time);
+
+  packer.pop();
+  bool pack_ok = packer.end_pack();
+  nassertv(pack_ok);
+
+  Datagram dg(packer.get_data(), packer.get_length());
+  _repository->send_datagram(dg);
+}
+

+ 98 - 0
direct/src/distributed/cDistributedSmoothNodeBase.h

@@ -0,0 +1,98 @@
+// Filename: cDistributedSmoothNodeBase.h
+// Created by:  drose (03Sep04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CDISTRIBUTEDSMOOTHNODEBASE_H
+#define CDISTRIBUTEDSMOOTHNODEBASE_H
+
+#include "directbase.h"
+#include "nodePath.h"
+#include "dcbase.h"
+#include "dcPacker.h"
+#include "dcPython.h"  // to pick up Python.h
+
+class DCClass;
+class CConnectionRepository;
+
+////////////////////////////////////////////////////////////////////
+//       Class : CDistributedSmoothNodeBase
+// Description : This class defines some basic methods of
+//               DistributedSmoothNodeBase which have been moved into
+//               C++ as a performance optimization.
+////////////////////////////////////////////////////////////////////
+class EXPCL_DIRECT CDistributedSmoothNodeBase {
+PUBLISHED:
+  CDistributedSmoothNodeBase();
+  ~CDistributedSmoothNodeBase();
+  
+  INLINE static void
+  set_repository(CConnectionRepository *repository,
+                 bool is_ai, CHANNEL_TYPE ai_id);
+
+  INLINE static void
+  set_clock_delta(PyObject *clock_delta);
+
+  void initialize(const NodePath &node_path, DCClass *dclass,
+                  CHANNEL_TYPE do_id);
+
+  void send_everything();
+
+  void broadcast_pos_hpr_full();
+  void broadcast_pos_hpr_xyh();
+
+private:
+  INLINE static bool only_changed(int flags, int compare);
+
+  INLINE void d_setSmStop();
+  INLINE void d_setSmH(float h);
+  INLINE void d_setSmXY(float x, float y);
+  INLINE void d_setSmXZ(float x, float z);
+  INLINE void d_setSmPos(float x, float y, float z);
+  INLINE void d_setSmHpr(float h, float p, float r);
+  INLINE void d_setSmXYH(float x, float y, float h);
+  INLINE void d_setSmXYZH(float x, float y, float z, float h);
+  INLINE void d_setSmPosHpr(float x, float y, float z, float h, float p, float r);
+
+  void begin_send_update(DCPacker &packer, const string &field_name);
+  void finish_send_update(DCPacker &packer);
+
+  enum Flags {
+    F_new_x     = 0x01,
+    F_new_y     = 0x02,
+    F_new_z     = 0x04,
+    F_new_h     = 0x08,
+    F_new_p     = 0x10,
+    F_new_r     = 0x20,
+  };
+
+  NodePath _node_path;
+  DCClass *_dclass;
+  CHANNEL_TYPE _do_id;
+
+  static CConnectionRepository *_repository;
+  static bool _is_ai;
+  static CHANNEL_TYPE _ai_id;
+  static PyObject *_clock_delta;
+
+  LPoint3f _store_xyz;
+  LVecBase3f _store_hpr;
+  bool _store_stop;
+};
+
+#include "cDistributedSmoothNodeBase.I"
+
+#endif  // CDISTRIBUTEDSMOOTHNODEBASE_H