Browse Source

replace set_velocity() with set_fluid_pos()

David Rose 22 years ago
parent
commit
3c3f2f4432
33 changed files with 734 additions and 550 deletions
  1. 6 2
      direct/src/directutil/Mopath.py
  2. 30 22
      direct/src/interval/LerpInterval.py
  3. 17 1
      direct/src/interval/cLerpNodePathInterval.cxx
  4. 2 0
      direct/src/interval/cLerpNodePathInterval.h
  5. 1 3
      direct/src/showbase/NonPhysicsWalker.py
  6. 0 5
      direct/src/showbase/PhysicsWalker.py
  7. 15 0
      direct/src/showbase/ShowBase.py
  8. 2 0
      direct/src/tkpanels/TaskManagerPanel.py
  9. 117 65
      panda/src/collide/collisionEntry.I
  10. 3 1
      panda/src/collide/collisionEntry.cxx
  11. 19 13
      panda/src/collide/collisionEntry.h
  12. 1 0
      panda/src/collide/collisionHandlerFloor.cxx
  13. 32 6
      panda/src/collide/collisionLevelState.I
  14. 5 5
      panda/src/collide/collisionLevelState.cxx
  15. 10 5
      panda/src/collide/collisionLevelState.h
  16. 7 2
      panda/src/collide/collisionNode.cxx
  17. 5 5
      panda/src/collide/collisionPlane.cxx
  18. 11 11
      panda/src/collide/collisionPolygon.cxx
  19. 7 7
      panda/src/collide/collisionSphere.cxx
  20. 30 0
      panda/src/collide/collisionTraverser.I
  21. 63 39
      panda/src/collide/collisionTraverser.cxx
  22. 7 0
      panda/src/collide/collisionTraverser.h
  23. 9 9
      panda/src/collide/collisionTube.cxx
  24. 0 5
      panda/src/collide/config_collide.cxx
  25. 0 2
      panda/src/collide/config_collide.h
  26. 2 0
      panda/src/pgraph/accumulatedAttribs.cxx
  27. 59 56
      panda/src/pgraph/nodePath.I
  28. 206 153
      panda/src/pgraph/nodePath.cxx
  29. 21 23
      panda/src/pgraph/nodePath.h
  30. 42 59
      panda/src/pgraph/pandaNode.I
  31. 5 8
      panda/src/pgraph/pandaNode.h
  32. 0 38
      panda/src/tform/transform2sg.cxx
  33. 0 5
      panda/src/tform/transform2sg.h

+ 6 - 2
direct/src/directutil/Mopath.py

@@ -7,11 +7,12 @@ class Mopath(PandaObject):
 
 
     nameIndex = 1
     nameIndex = 1
 
 
-    def __init__(self, name = None):
+    def __init__(self, name = None, fluid = 1):
         if (name == None):
         if (name == None):
             name = 'mopath%d' % self.nameIndex
             name = 'mopath%d' % self.nameIndex
             self.nameIndex = self.nameIndex + 1
             self.nameIndex = self.nameIndex + 1
         self.name = name
         self.name = name
+        self.fluid = fluid
         self.tPoint = Point3(0)
         self.tPoint = Point3(0)
         self.posPoint = Point3(0)
         self.posPoint = Point3(0)
         self.hprPoint = Point3(0)
         self.hprPoint = Point3(0)
@@ -97,7 +98,10 @@ class Mopath(PandaObject):
         self.playbackTime = self.calcTime(CLAMP(time, 0.0, self.maxT))
         self.playbackTime = self.calcTime(CLAMP(time, 0.0, self.maxT))
         if (self.xyzNurbsCurve != None):
         if (self.xyzNurbsCurve != None):
             self.xyzNurbsCurve.getPoint(self.playbackTime, self.posPoint)
             self.xyzNurbsCurve.getPoint(self.playbackTime, self.posPoint)
-            node.setPos(self.posPoint)
+            if self.fluid:
+                node.setFluidPos(self.posPoint)
+            else:
+                node.setPos(self.posPoint)
         if (self.hprNurbsCurve != None):
         if (self.hprNurbsCurve != None):
             self.hprNurbsCurve.getPoint(self.playbackTime, self.hprPoint)
             self.hprNurbsCurve.getPoint(self.playbackTime, self.hprPoint)
             node.setHpr(self.hprPoint)
             node.setHpr(self.hprPoint)

+ 30 - 22
direct/src/interval/LerpInterval.py

@@ -17,7 +17,8 @@ class LerpNodePathInterval(CLerpNodePathInterval):
     # affect a property on a NodePath, like pos or hpr.
     # affect a property on a NodePath, like pos or hpr.
     lerpNodePathNum = 1
     lerpNodePathNum = 1
 
 
-    def __init__(self, name, duration, blendType, bakeInStart, node, other):
+    def __init__(self, name, duration, blendType, bakeInStart, fluid,
+                 node, other):
         if name == None:
         if name == None:
             name = '%s-%d' % (self.__class__.__name__, self.lerpNodePathNum)
             name = '%s-%d' % (self.__class__.__name__, self.lerpNodePathNum)
             LerpNodePathInterval.lerpNodePathNum += 1
             LerpNodePathInterval.lerpNodePathNum += 1
@@ -29,7 +30,7 @@ class LerpNodePathInterval(CLerpNodePathInterval):
             other = NodePath()
             other = NodePath()
 
 
         CLerpNodePathInterval.__init__(self, name, duration, blendType,
         CLerpNodePathInterval.__init__(self, name, duration, blendType,
-                                       bakeInStart, node, other)
+                                       bakeInStart, fluid, node, other)
 
 
     def anyCallable(self, *params):
     def anyCallable(self, *params):
         # Returns true if any of the parameters listed is a callable
         # Returns true if any of the parameters listed is a callable
@@ -70,14 +71,21 @@ class LerpNodePathInterval(CLerpNodePathInterval):
 ##  delta since the last time the interval ran, which allows show code
 ##  delta since the last time the interval ran, which allows show code
 ##  to manipulate the node even while it is being lerped.
 ##  to manipulate the node even while it is being lerped.
 ##
 ##
+##  If fluid is true for a LerpPos-style interval, then the pos is set
+##  via NodePath.setFluidPos() instead of NodePath.setPos(), causing
+##  the collision system to treat the motion as continuous and test
+##  for collisions against the entire motion path, instead of as
+##  discrete position updates.  This has no meaning for Lerp intervals
+##  that do not adjust pos.
+##
 #####################################################################
 #####################################################################
 
 
 class LerpPosInterval(LerpNodePathInterval):
 class LerpPosInterval(LerpNodePathInterval):
     def __init__(self, node, duration, pos, startPos = None,
     def __init__(self, node, duration, pos, startPos = None,
                  other = None, blendType = 'noBlend',
                  other = None, blendType = 'noBlend',
-                 bakeInStart = 1, name = None):
+                 bakeInStart = 1, fluid = 0, name = None):
         LerpNodePathInterval.__init__(self, name, duration, blendType,
         LerpNodePathInterval.__init__(self, name, duration, blendType,
-                                      bakeInStart, node, other)
+                                      bakeInStart, fluid, node, other)
 
 
         # Check for functors in the input parameters.
         # Check for functors in the input parameters.
         self.paramSetup = self.anyCallable(pos, startPos)
         self.paramSetup = self.anyCallable(pos, startPos)
@@ -102,9 +110,9 @@ class LerpPosInterval(LerpNodePathInterval):
 class LerpHprInterval(LerpNodePathInterval):
 class LerpHprInterval(LerpNodePathInterval):
     def __init__(self, node, duration, hpr, startHpr = None,
     def __init__(self, node, duration, hpr, startHpr = None,
                  other = None, blendType = 'noBlend',
                  other = None, blendType = 'noBlend',
-                 bakeInStart = 1, name = None):
+                 bakeInStart = 1, fluid = 0, name = None):
         LerpNodePathInterval.__init__(self, name, duration, blendType,
         LerpNodePathInterval.__init__(self, name, duration, blendType,
-                                      bakeInStart, node, other)
+                                      bakeInStart, fluid, node, other)
 
 
         # Check for functors in the input parameters.
         # Check for functors in the input parameters.
         self.paramSetup = self.anyCallable(hpr, startHpr)
         self.paramSetup = self.anyCallable(hpr, startHpr)
@@ -128,9 +136,9 @@ class LerpHprInterval(LerpNodePathInterval):
 class LerpScaleInterval(LerpNodePathInterval):
 class LerpScaleInterval(LerpNodePathInterval):
     def __init__(self, node, duration, scale, startScale = None,
     def __init__(self, node, duration, scale, startScale = None,
                  other = None, blendType = 'noBlend',
                  other = None, blendType = 'noBlend',
-                 bakeInStart = 1, name = None):
+                 bakeInStart = 1, fluid = 0, name = None):
         LerpNodePathInterval.__init__(self, name, duration, blendType,
         LerpNodePathInterval.__init__(self, name, duration, blendType,
-                                      bakeInStart, node, other)
+                                      bakeInStart, fluid, node, other)
         # Check for functors in the input parameters.
         # Check for functors in the input parameters.
         self.paramSetup = self.anyCallable(scale, startScale)
         self.paramSetup = self.anyCallable(scale, startScale)
         if self.paramSetup:
         if self.paramSetup:
@@ -153,9 +161,9 @@ class LerpScaleInterval(LerpNodePathInterval):
 class LerpShearInterval(LerpNodePathInterval):
 class LerpShearInterval(LerpNodePathInterval):
     def __init__(self, node, duration, shear, startShear = None,
     def __init__(self, node, duration, shear, startShear = None,
                  other = None, blendType = 'noBlend',
                  other = None, blendType = 'noBlend',
-                 bakeInStart = 1, name = None):
+                 bakeInStart = 1, fluid = 0, name = None):
         LerpNodePathInterval.__init__(self, name, duration, blendType,
         LerpNodePathInterval.__init__(self, name, duration, blendType,
-                                      bakeInStart, node, other)
+                                      bakeInStart, fluid, node, other)
         # Check for functors in the input parameters.
         # Check for functors in the input parameters.
         self.paramSetup = self.anyCallable(shear, startShear)
         self.paramSetup = self.anyCallable(shear, startShear)
         if self.paramSetup:
         if self.paramSetup:
@@ -179,9 +187,9 @@ class LerpPosHprInterval(LerpNodePathInterval):
     def __init__(self, node, duration, pos, hpr,
     def __init__(self, node, duration, pos, hpr,
                  startPos = None, startHpr = None,
                  startPos = None, startHpr = None,
                  other = None, blendType = 'noBlend',
                  other = None, blendType = 'noBlend',
-                 bakeInStart = 1, name = None):
+                 bakeInStart = 1, fluid = 0, name = None):
         LerpNodePathInterval.__init__(self, name, duration, blendType,
         LerpNodePathInterval.__init__(self, name, duration, blendType,
-                                      bakeInStart, node, other)
+                                      bakeInStart, fluid, node, other)
         # Check for functors in the input parameters.
         # Check for functors in the input parameters.
         self.paramSetup = self.anyCallable(pos, startPos, hpr, startHpr)
         self.paramSetup = self.anyCallable(pos, startPos, hpr, startHpr)
         if self.paramSetup:
         if self.paramSetup:
@@ -212,9 +220,9 @@ class LerpHprScaleInterval(LerpNodePathInterval):
     def __init__(self, node, duration, hpr, scale,
     def __init__(self, node, duration, hpr, scale,
                  startHpr = None, startScale = None,
                  startHpr = None, startScale = None,
                  other = None, blendType = 'noBlend',
                  other = None, blendType = 'noBlend',
-                 bakeInStart = 1, name = None):
+                 bakeInStart = 1, fluid = 0, name = None):
         LerpNodePathInterval.__init__(self, name, duration, blendType,
         LerpNodePathInterval.__init__(self, name, duration, blendType,
-                                      bakeInStart, node, other)
+                                      bakeInStart, fluid, node, other)
 
 
         # Check for functors in the input parameters.
         # Check for functors in the input parameters.
         self.paramSetup = self.anyCallable(hpr, startHpr, scale, startScale)
         self.paramSetup = self.anyCallable(hpr, startHpr, scale, startScale)
@@ -246,9 +254,9 @@ class LerpPosHprScaleInterval(LerpNodePathInterval):
     def __init__(self, node, duration, pos, hpr, scale,
     def __init__(self, node, duration, pos, hpr, scale,
                  startPos = None, startHpr = None, startScale = None,
                  startPos = None, startHpr = None, startScale = None,
                  other = None, blendType = 'noBlend',
                  other = None, blendType = 'noBlend',
-                 bakeInStart = 1, name = None):
+                 bakeInStart = 1, fluid = 0, name = None):
         LerpNodePathInterval.__init__(self, name, duration, blendType,
         LerpNodePathInterval.__init__(self, name, duration, blendType,
-                                      bakeInStart, node, other)
+                                      bakeInStart, fluid, node, other)
         # Check for functors in the input parameters.
         # Check for functors in the input parameters.
         self.paramSetup = self.anyCallable(pos, startPos, hpr, startHpr, scale, startScale)
         self.paramSetup = self.anyCallable(pos, startPos, hpr, startHpr, scale, startScale)
         if self.paramSetup:
         if self.paramSetup:
@@ -286,9 +294,9 @@ class LerpPosHprScaleShearInterval(LerpNodePathInterval):
     def __init__(self, node, duration, pos, hpr, scale, shear,
     def __init__(self, node, duration, pos, hpr, scale, shear,
                  startPos = None, startHpr = None, startScale = None, startShear = None,
                  startPos = None, startHpr = None, startScale = None, startShear = None,
                  other = None, blendType = 'noBlend',
                  other = None, blendType = 'noBlend',
-                 bakeInStart = 1, name = None):
+                 bakeInStart = 1, fluid = 0, name = None):
         LerpNodePathInterval.__init__(self, name, duration, blendType,
         LerpNodePathInterval.__init__(self, name, duration, blendType,
-                                      bakeInStart, node, other)
+                                      bakeInStart, fluid, node, other)
         # Check for functors in the input parameters.
         # Check for functors in the input parameters.
         self.paramSetup = self.anyCallable(pos, startPos, hpr, startHpr, scale, startScale, shear, startShear)
         self.paramSetup = self.anyCallable(pos, startPos, hpr, startHpr, scale, startScale, shear, startShear)
         if self.paramSetup:
         if self.paramSetup:
@@ -332,9 +340,9 @@ class LerpPosHprScaleShearInterval(LerpNodePathInterval):
 class LerpColorScaleInterval(LerpNodePathInterval):
 class LerpColorScaleInterval(LerpNodePathInterval):
     def __init__(self, node, duration, colorScale, startColorScale = None,
     def __init__(self, node, duration, colorScale, startColorScale = None,
                  other = None, blendType = 'noBlend',
                  other = None, blendType = 'noBlend',
-                 bakeInStart = 1, name = None):
+                 bakeInStart = 1, fluid = 0, name = None):
         LerpNodePathInterval.__init__(self, name, duration, blendType,
         LerpNodePathInterval.__init__(self, name, duration, blendType,
-                                      bakeInStart, node, other)
+                                      bakeInStart, fluid, node, other)
         self.setEndColorScale(colorScale)
         self.setEndColorScale(colorScale)
         if startColorScale != None:
         if startColorScale != None:
             self.setStartColorScale(startColorScale)
             self.setStartColorScale(startColorScale)
@@ -342,9 +350,9 @@ class LerpColorScaleInterval(LerpNodePathInterval):
 class LerpColorInterval(LerpNodePathInterval):
 class LerpColorInterval(LerpNodePathInterval):
     def __init__(self, node, duration, color, startColor = None,
     def __init__(self, node, duration, color, startColor = None,
                  other = None, blendType = 'noBlend',
                  other = None, blendType = 'noBlend',
-                 bakeInStart = 1, name = None):
+                 bakeInStart = 1, fluid = 0, name = None):
         LerpNodePathInterval.__init__(self, name, duration, blendType,
         LerpNodePathInterval.__init__(self, name, duration, blendType,
-                                      bakeInStart, node, other)
+                                      bakeInStart, fluid, node, other)
         self.setEndColor(color)
         self.setEndColor(color)
         if startColor != None:
         if startColor != None:
             self.setStartColor(startColor)
             self.setStartColor(startColor)

+ 17 - 1
direct/src/interval/cLerpNodePathInterval.cxx

@@ -54,11 +54,14 @@ TypeHandle CLerpNodePathInterval::_type_handle;
 //               "smart" behavior allows code to manipulate the object
 //               "smart" behavior allows code to manipulate the object
 //               event while it is being lerped, and the lerp
 //               event while it is being lerped, and the lerp
 //               continues to apply in a sensible way.
 //               continues to apply in a sensible way.
+//
+//               If fluid is true, the prev_transform is not adjusted
+//               by the lerp; otherwise, it is reset.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CLerpNodePathInterval::
 CLerpNodePathInterval::
 CLerpNodePathInterval(const string &name, double duration, 
 CLerpNodePathInterval(const string &name, double duration, 
                       CLerpInterval::BlendType blend_type,
                       CLerpInterval::BlendType blend_type,
-                      bool bake_in_start,
+                      bool bake_in_start, bool fluid,
                       const NodePath &node, const NodePath &other) :
                       const NodePath &node, const NodePath &other) :
   CLerpInterval(name, duration, blend_type),
   CLerpInterval(name, duration, blend_type),
   _node(node),
   _node(node),
@@ -68,6 +71,9 @@ CLerpNodePathInterval(const string &name, double duration,
   if (bake_in_start) {
   if (bake_in_start) {
     _flags |= F_bake_in_start;
     _flags |= F_bake_in_start;
   }
   }
+  if (fluid) {
+    _flags |= F_fluid;
+  }
   _prev_d = 0.0;
   _prev_d = 0.0;
 }
 }
 
 
@@ -119,6 +125,9 @@ priv_step(double t) {
   _state = S_started;
   _state = S_started;
   double d = compute_delta(t);
   double d = compute_delta(t);
 
 
+  // Save this in case we want to restore it later.
+  CPT(TransformState) prev_transform = _node.get_prev_transform();
+
   if ((_flags & (F_end_pos | F_end_hpr | F_end_scale | F_end_shear)) != 0) {
   if ((_flags & (F_end_pos | F_end_hpr | F_end_scale | F_end_shear)) != 0) {
     // We have some transform lerp.
     // We have some transform lerp.
     CPT(TransformState) transform;
     CPT(TransformState) transform;
@@ -297,6 +306,13 @@ priv_step(double t) {
     }
     }
   }
   }
 
 
+  if ((_flags & F_fluid) != 0) {
+    // If we have the fluid flag set, we shouldn't mess with the prev
+    // transform.  Therefore, restore it to what it was before we
+    // started messing with it.
+    _node.set_prev_transform(prev_transform);
+  }
+
   if ((_flags & (F_end_color | F_end_color_scale)) != 0) {
   if ((_flags & (F_end_color | F_end_color_scale)) != 0) {
     // We have some render state lerp.
     // We have some render state lerp.
     CPT(RenderState) state;
     CPT(RenderState) state;

+ 2 - 0
direct/src/interval/cLerpNodePathInterval.h

@@ -32,6 +32,7 @@ class EXPCL_DIRECT CLerpNodePathInterval : public CLerpInterval {
 PUBLISHED:
 PUBLISHED:
   CLerpNodePathInterval(const string &name, double duration, 
   CLerpNodePathInterval(const string &name, double duration, 
                         BlendType blend_type, bool bake_in_start,
                         BlendType blend_type, bool bake_in_start,
+                        bool fluid,
                         const NodePath &node, const NodePath &other);
                         const NodePath &node, const NodePath &other);
 
 
   INLINE const NodePath &get_node() const;
   INLINE const NodePath &get_node() const;
@@ -79,6 +80,7 @@ private:
     F_start_color_scale  = 0x1000,
     F_start_color_scale  = 0x1000,
     F_start_shear        = 0x2000,
     F_start_shear        = 0x2000,
 
 
+    F_fluid              = 0x4000,
     F_bake_in_start      = 0x8000,
     F_bake_in_start      = 0x8000,
   };
   };
   
   

+ 1 - 3
direct/src/showbase/NonPhysicsWalker.py

@@ -179,13 +179,11 @@ class NonPhysicsWalker(DirectObject.DirectObject):
                 # our previous heading.
                 # our previous heading.
                 rotMat=Mat3.rotateMatNormaxis(self.avatarNodePath.getH(), Vec3.up())
                 rotMat=Mat3.rotateMatNormaxis(self.avatarNodePath.getH(), Vec3.up())
                 step=rotMat.xform(self.vel)
                 step=rotMat.xform(self.vel)
-                self.avatarNodePath.setPos(Point3(self.avatarNodePath.getPos()+step))
+                self.avatarNodePath.setFluidPos(Point3(self.avatarNodePath.getPos()+step))
             self.avatarNodePath.setH(self.avatarNodePath.getH()+rotation)
             self.avatarNodePath.setH(self.avatarNodePath.getH()+rotation)
             messenger.send("avatarMoving")
             messenger.send("avatarMoving")
         else:
         else:
             self.vel.set(0.0, 0.0, 0.0)
             self.vel.set(0.0, 0.0, 0.0)
-        # Set collision sphere node:
-        self.cSphereNode.setVelocity(self.vel)
         return Task.cont
         return Task.cont
 
 
     def enableAvatarControls(self):
     def enableAvatarControls(self):

+ 0 - 5
direct/src/showbase/PhysicsWalker.py

@@ -305,17 +305,12 @@ class PhysicsWalker(DirectObject.DirectObject):
             self.__vel.set(0.0, 0.0, 0.0)
             self.__vel.set(0.0, 0.0, 0.0)
         # Clear the contact vector so we can tell if we contact something next frame:
         # Clear the contact vector so we can tell if we contact something next frame:
         self.actorNode.setContactVector(Vec3.zero())
         self.actorNode.setContactVector(Vec3.zero())
-        # Set collision sphere node:
-        v=physObject.getImplicitVelocity()
-        v=rotAvatarToPhys.xform(v)
-        self.cSphereNode.setVelocity(Vec3(v))
         return Task.cont
         return Task.cont
     
     
     def resetPhys(self):
     def resetPhys(self):
         assert(self.debugPrint("resetPhys()"))
         assert(self.debugPrint("resetPhys()"))
         self.actorNode.getPhysicsObject().resetPosition(self.avatarNodePath.getPos())
         self.actorNode.getPhysicsObject().resetPosition(self.avatarNodePath.getPos())
         self.actorNode.setContactVector(Vec3.zero())
         self.actorNode.setContactVector(Vec3.zero())
-        self.cSphereNode.setVelocity(Vec3(0.0))
 
 
     def enableAvatarControls(self):
     def enableAvatarControls(self):
         """
         """

+ 15 - 0
direct/src/showbase/ShowBase.py

@@ -793,6 +793,18 @@ class ShowBase(DirectObject.DirectObject):
                 music.setLoop(looping)
                 music.setLoop(looping)
                 music.play()
                 music.play()
 
 
+    def resetPrevTransform(self, state):
+        # Clear out the previous velocity deltas now, after we have
+        # rendered (the previous frame).  We do this after the render,
+        # so that we have a chance to draw a representation of spheres
+        # along with their velocities.  At the beginning of the frame
+        # really means after the command prompt, which allows the user
+        # to interactively query these deltas meaningfully.
+        
+        if self.cTrav:
+            self.cTrav.resetPrevTransform(self.render)
+        return Task.cont
+
     def dataloop(self, state):
     def dataloop(self, state):
         # traverse the data graph.  This reads all the control
         # traverse the data graph.  This reads all the control
         # inputs (from the mouse and keyboard, for instance) and also
         # inputs (from the mouse and keyboard, for instance) and also
@@ -845,6 +857,8 @@ class ShowBase(DirectObject.DirectObject):
 
 
     def restart(self):
     def restart(self):
         self.shutdown()
         self.shutdown()
+        # resetPrevTransform goes at the very beginning of the frame.
+        self.taskMgr.add(self.resetPrevTransform, 'resetPrevTransform', priority = -51)
         # give the dataloop task a reasonably "early" priority,
         # give the dataloop task a reasonably "early" priority,
         # so that it will get run before most tasks
         # so that it will get run before most tasks
         self.taskMgr.add(self.dataloop, 'dataloop', priority = -50)
         self.taskMgr.add(self.dataloop, 'dataloop', priority = -50)
@@ -868,6 +882,7 @@ class ShowBase(DirectObject.DirectObject):
         self.taskMgr.remove('shadowCollisionLoop')
         self.taskMgr.remove('shadowCollisionLoop')
         self.taskMgr.remove('collisionloop')
         self.taskMgr.remove('collisionloop')
         self.taskMgr.remove('dataloop')
         self.taskMgr.remove('dataloop')
+        self.taskMgr.remove('resetPrevTransform')
         self.taskMgr.remove('ivalloop')
         self.taskMgr.remove('ivalloop')
         self.eventMgr.shutdown()
         self.eventMgr.shutdown()
 
 

+ 2 - 0
direct/src/tkpanels/TaskManagerPanel.py

@@ -179,6 +179,7 @@ class TaskManagerWidget(PandaObject):
             name = self.currentTask.name
             name = self.currentTask.name
             ok = 1
             ok = 1
             if ((name == 'dataloop') or
             if ((name == 'dataloop') or
+                (name == 'resetPrevTransform') or
                 (name == 'tkloop') or
                 (name == 'tkloop') or
                 (name == 'eventManager') or
                 (name == 'eventManager') or
                 (name == 'igloop')):
                 (name == 'igloop')):
@@ -195,6 +196,7 @@ class TaskManagerWidget(PandaObject):
         name = self.taskListBox.getcurselection()[0]
         name = self.taskListBox.getcurselection()[0]
         ok = 1
         ok = 1
         if ((name == 'dataloop') or
         if ((name == 'dataloop') or
+            (name == 'resetPrevTransform') or
             (name == 'tkloop') or
             (name == 'tkloop') or
             (name == 'eventManager') or
             (name == 'eventManager') or
             (name == 'igloop')):
             (name == 'igloop')):

+ 117 - 65
panda/src/collide/collisionEntry.I

@@ -19,17 +19,21 @@
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::Constructor
 //     Function: CollisionEntry::Constructor
-//       Access: Public
+//       Access: Published
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE CollisionEntry::
 INLINE CollisionEntry::
 CollisionEntry() {
 CollisionEntry() {
   _flags = 0;
   _flags = 0;
+  _from_space = TransformState::make_identity();
+  _into_space = TransformState::make_identity();
+  _wrt_space = TransformState::make_identity();
+  _inv_wrt_space = TransformState::make_identity();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::get_from
 //     Function: CollisionEntry::get_from
-//       Access: Public
+//       Access: Published
 //  Description: Returns the CollisionSolid pointer for the particular
 //  Description: Returns the CollisionSolid pointer for the particular
 //               solid that triggered this collision.
 //               solid that triggered this collision.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -40,7 +44,7 @@ get_from() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::has_into
 //     Function: CollisionEntry::has_into
-//       Access: Public
+//       Access: Published
 //  Description: Returns true if the "into" solid is, in fact, a
 //  Description: Returns true if the "into" solid is, in fact, a
 //               CollisionSolid, and its pointer is known (in which
 //               CollisionSolid, and its pointer is known (in which
 //               case get_into() may be called to retrieve it).  If
 //               case get_into() may be called to retrieve it).  If
@@ -55,7 +59,7 @@ has_into() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::get_into
 //     Function: CollisionEntry::get_into
-//       Access: Public
+//       Access: Published
 //  Description: Returns the CollisionSolid pointer for the particular
 //  Description: Returns the CollisionSolid pointer for the particular
 //               solid was collided into.  This pointer might be NULL
 //               solid was collided into.  This pointer might be NULL
 //               if the collision was into a piece of visible
 //               if the collision was into a piece of visible
@@ -69,7 +73,7 @@ get_into() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::get_from_node
 //     Function: CollisionEntry::get_from_node
-//       Access: Public
+//       Access: Published
 //  Description: Returns the node that contains the CollisionSolid
 //  Description: Returns the node that contains the CollisionSolid
 //               that triggered this collision.  This will be a node
 //               that triggered this collision.  This will be a node
 //               that has been added to a CollisionTraverser via
 //               that has been added to a CollisionTraverser via
@@ -80,22 +84,9 @@ get_from_node() const {
   return _from_node;
   return _from_node;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: CollisionEntry::get_from_space
-//       Access: Public
-//  Description: Returns the global coordinate space of the
-//               CollisionNode returned by get_from_node(), as of the
-//               time of the collision.  This will be equivalent to a
-//               wrt() from the node to render.
-////////////////////////////////////////////////////////////////////
-INLINE const LMatrix4f &CollisionEntry::
-get_from_space() const {
-  return _from_space;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::get_into_node
 //     Function: CollisionEntry::get_into_node
-//       Access: Public
+//       Access: Published
 //  Description: Returns the node that contains the CollisionSolid
 //  Description: Returns the node that contains the CollisionSolid
 //               that was collided into.  This returns a PandaNode
 //               that was collided into.  This returns a PandaNode
 //               pointer instead of something more specific, because
 //               pointer instead of something more specific, because
@@ -110,7 +101,7 @@ get_into_node() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::get_into_node_path
 //     Function: CollisionEntry::get_into_node_path
-//       Access: Public
+//       Access: Published
 //  Description: Returns the NodePath that represents the specific
 //  Description: Returns the NodePath that represents the specific
 //               CollisionNode or GeomNode instance that was collided
 //               CollisionNode or GeomNode instance that was collided
 //               into.  This is the same node returned by
 //               into.  This is the same node returned by
@@ -124,78 +115,139 @@ get_into_node_path() const {
   return _into_node_path;
   return _into_node_path;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: CollisionEntry::get_from_space
+//       Access: Published
+//  Description: Returns the global coordinate space of the
+//               CollisionNode returned by get_from_node(), as of the
+//               time of the collision.  This will be equivalent to a
+//               wrt() from the node to render.
+////////////////////////////////////////////////////////////////////
+INLINE const TransformState *CollisionEntry::
+get_from_space() const {
+  return _from_space;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::get_into_space
 //     Function: CollisionEntry::get_into_space
-//       Access: Public
+//       Access: Published
 //  Description: Returns the global coordinate space of the
 //  Description: Returns the global coordinate space of the
 //               CollisionNode or GeomNode returned by
 //               CollisionNode or GeomNode returned by
 //               get_into_node(), as of the time of the collision.
 //               get_into_node(), as of the time of the collision.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE const LMatrix4f &CollisionEntry::
+INLINE const TransformState *CollisionEntry::
 get_into_space() const {
 get_into_space() const {
   return _into_space;
   return _into_space;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::get_wrt_space
 //     Function: CollisionEntry::get_wrt_space
-//       Access: Public
+//       Access: Published
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE const LMatrix4f &CollisionEntry::
+INLINE const TransformState *CollisionEntry::
 get_wrt_space() const {
 get_wrt_space() const {
   return _wrt_space;
   return _wrt_space;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::get_inv_wrt_space
 //     Function: CollisionEntry::get_inv_wrt_space
-//       Access: Public
+//       Access: Published
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE const LMatrix4f &CollisionEntry::
+INLINE const TransformState *CollisionEntry::
 get_inv_wrt_space() const {
 get_inv_wrt_space() const {
   return _inv_wrt_space;
   return _inv_wrt_space;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CollisionEntry::set_from_velocity
-//       Access: Public
-//  Description: Indicates the velocity associated with the "from"
+//     Function: CollisionEntry::get_from_mat
+//       Access: Published
+//  Description: Returns the global coordinate space of the
+//               CollisionNode returned by get_from_node(), as of the
+//               time of the collision.  This will be equivalent to a
+//               wrt() from the node to render.
+////////////////////////////////////////////////////////////////////
+INLINE const LMatrix4f &CollisionEntry::
+get_from_mat() const {
+  return _from_space->get_mat();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CollisionEntry::get_into_mat
+//       Access: Published
+//  Description: Returns the global coordinate space of the
+//               CollisionNode or GeomNode returned by
+//               get_into_node(), as of the time of the collision.
+////////////////////////////////////////////////////////////////////
+INLINE const LMatrix4f &CollisionEntry::
+get_into_mat() const {
+  return _into_space->get_mat();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CollisionEntry::get_wrt_mat
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE const LMatrix4f &CollisionEntry::
+get_wrt_mat() const {
+  return _wrt_space->get_mat();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CollisionEntry::get_inv_wrt_mat
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE const LMatrix4f &CollisionEntry::
+get_inv_wrt_mat() const {
+  return _inv_wrt_space->get_mat();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CollisionEntry::set_from_pos_delta
+//       Access: Published
+//  Description: Indicates the pos_delta associated with the "from"
 //               object, in the object's coordinate space.
 //               object, in the object's coordinate space.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void CollisionEntry::
 INLINE void CollisionEntry::
-set_from_velocity(const LVector3f &vel) {
-  _from_velocity = vel;
-  _flags |= F_has_from_velocity;
+set_from_pos_delta(const LVector3f &vel) {
+  _from_pos_delta = vel;
+  _flags |= F_has_from_pos_delta;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CollisionEntry::has_from_velocity
-//       Access: Public
-//  Description: Returns true if the "from" object had an indicated
-//               velocity, false otherwise.
+//     Function: CollisionEntry::has_from_pos_delta
+//       Access: Published
+//  Description: Returns true if the objects appeared to be moving
+//               relative to each other, false otherwise.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool CollisionEntry::
 INLINE bool CollisionEntry::
-has_from_velocity() const {
-  return (_flags & F_has_from_velocity) != 0;
+has_from_pos_delta() const {
+  return (_flags & F_has_from_pos_delta) != 0;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CollisionEntry::get_from_velocity
-//       Access: Public
-//  Description: Returns the instantaneous velocity of the "from"
-//               object, in its own coordinate space.  This represents
-//               the delta between its current position and its
-//               position last frame.
+//     Function: CollisionEntry::get_from_pos_delta
+//       Access: Published
+//  Description: Returns the position delta between the two objects,
+//               in the coordinate space of the "from" object.  This
+//               is the delta between their relative position in the
+//               previous frame and their relative position this
+//               frame.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE const LVector3f &CollisionEntry::
 INLINE const LVector3f &CollisionEntry::
-get_from_velocity() const {
-  nassertr(has_from_velocity(), _from_velocity);
-  return _from_velocity;
+get_from_pos_delta() const {
+  if (!has_from_pos_delta()) {
+    return LVector3f::zero();
+  }
+  return _from_pos_delta;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::set_into_intersection_point
 //     Function: CollisionEntry::set_into_intersection_point
-//       Access: Public
+//       Access: Published
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void CollisionEntry::
 INLINE void CollisionEntry::
@@ -206,7 +258,7 @@ set_into_intersection_point(const LPoint3f &point) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::has_into_intersection_point
 //     Function: CollisionEntry::has_into_intersection_point
-//       Access: Public
+//       Access: Published
 //  Description: Returns true if the detected collision knows its
 //  Description: Returns true if the detected collision knows its
 //               intersection point in the coordinate space of the
 //               intersection point in the coordinate space of the
 //               collided-into object, false otherwise.
 //               collided-into object, false otherwise.
@@ -218,7 +270,7 @@ has_into_intersection_point() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::get_into_intersection_point
 //     Function: CollisionEntry::get_into_intersection_point
-//       Access: Public
+//       Access: Published
 //  Description: Returns the intersection point in the coordinate
 //  Description: Returns the intersection point in the coordinate
 //               space of the collided-into object.  It is an error to
 //               space of the collided-into object.  It is an error to
 //               call this if has_into_intersection_point() returns
 //               call this if has_into_intersection_point() returns
@@ -232,7 +284,7 @@ get_into_intersection_point() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::has_from_intersection_point
 //     Function: CollisionEntry::has_from_intersection_point
-//       Access: Public
+//       Access: Published
 //  Description: Returns true if the detected collision knows its
 //  Description: Returns true if the detected collision knows its
 //               intersection point in the coordinate space of the
 //               intersection point in the coordinate space of the
 //               colliding object, false otherwise.
 //               colliding object, false otherwise.
@@ -246,7 +298,7 @@ has_from_intersection_point() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::get_from_intersection_point
 //     Function: CollisionEntry::get_from_intersection_point
-//       Access: Public
+//       Access: Published
 //  Description: Returns the intersection point in the coordinate
 //  Description: Returns the intersection point in the coordinate
 //               space of the colliding object.  It is an error to
 //               space of the colliding object.  It is an error to
 //               call this if has_from_intersection_point() returns
 //               call this if has_from_intersection_point() returns
@@ -254,12 +306,12 @@ has_from_intersection_point() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE LPoint3f CollisionEntry::
 INLINE LPoint3f CollisionEntry::
 get_from_intersection_point() const {
 get_from_intersection_point() const {
-  return get_into_intersection_point() * get_inv_wrt_space();
+  return get_into_intersection_point() * get_inv_wrt_mat();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::set_into_surface_normal
 //     Function: CollisionEntry::set_into_surface_normal
-//       Access: Public
+//       Access: Published
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void CollisionEntry::
 INLINE void CollisionEntry::
@@ -270,7 +322,7 @@ set_into_surface_normal(const LVector3f &normal) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::has_into_surface_normal
 //     Function: CollisionEntry::has_into_surface_normal
-//       Access: Public
+//       Access: Published
 //  Description: Returns true if the detected collision knows the
 //  Description: Returns true if the detected collision knows the
 //               surface normal of the collided-into object at the
 //               surface normal of the collided-into object at the
 //               point of the collision, false otherwise.
 //               point of the collision, false otherwise.
@@ -282,7 +334,7 @@ has_into_surface_normal() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::get_into_surface_normal
 //     Function: CollisionEntry::get_into_surface_normal
-//       Access: Public
+//       Access: Published
 //  Description: Returns the surface normal of the collided-into
 //  Description: Returns the surface normal of the collided-into
 //               object at the point of the collision.  It is an error
 //               object at the point of the collision.  It is an error
 //               to call this if has_into_surface_normal() returns
 //               to call this if has_into_surface_normal() returns
@@ -296,7 +348,7 @@ get_into_surface_normal() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::set_from_surface_normal
 //     Function: CollisionEntry::set_from_surface_normal
-//       Access: Public
+//       Access: Published
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void CollisionEntry::
 INLINE void CollisionEntry::
@@ -307,7 +359,7 @@ set_from_surface_normal(const LVector3f &normal) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::has_from_surface_normal
 //     Function: CollisionEntry::has_from_surface_normal
-//       Access: Public
+//       Access: Published
 //  Description: Returns true if the detected collision knows the
 //  Description: Returns true if the detected collision knows the
 //               surface normal of the collided-into object at the
 //               surface normal of the collided-into object at the
 //               point of the collision, false otherwise.
 //               point of the collision, false otherwise.
@@ -319,7 +371,7 @@ has_from_surface_normal() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::get_from_surface_normal
 //     Function: CollisionEntry::get_from_surface_normal
-//       Access: Public
+//       Access: Published
 //  Description: Returns the surface normal of the collided-into
 //  Description: Returns the surface normal of the collided-into
 //               object at the point of the collision, in the space of
 //               object at the point of the collision, in the space of
 //               the collided-from object.  It is an error to call
 //               the collided-from object.  It is an error to call
@@ -337,7 +389,7 @@ get_from_surface_normal() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::set_into_depth
 //     Function: CollisionEntry::set_into_depth
-//       Access: Public
+//       Access: Published
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void CollisionEntry::
 INLINE void CollisionEntry::
@@ -348,7 +400,7 @@ set_into_depth(float depth) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::has_into_depth
 //     Function: CollisionEntry::has_into_depth
-//       Access: Public
+//       Access: Published
 //  Description: Returns true if the collision entry knows how "deep"
 //  Description: Returns true if the collision entry knows how "deep"
 //               the collision was into the collided-into object; that
 //               the collision was into the collided-into object; that
 //               is, how far into the surface of the collided-into
 //               is, how far into the surface of the collided-into
@@ -361,7 +413,7 @@ has_into_depth() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::get_into_depth
 //     Function: CollisionEntry::get_into_depth
-//       Access: Public
+//       Access: Published
 //  Description: Returns how "deep" the collision was into the
 //  Description: Returns how "deep" the collision was into the
 //               collided-into object; that is, how far into the
 //               collided-into object; that is, how far into the
 //               surface of the collided-into object the colliding
 //               surface of the collided-into object the colliding
@@ -376,7 +428,7 @@ get_into_depth() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::set_from_depth
 //     Function: CollisionEntry::set_from_depth
-//       Access: Public
+//       Access: Published
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void CollisionEntry::
 INLINE void CollisionEntry::
@@ -387,7 +439,7 @@ set_from_depth(float depth) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::has_from_depth
 //     Function: CollisionEntry::has_from_depth
-//       Access: Public
+//       Access: Published
 //  Description: Returns true if the collision entry knows how "deep"
 //  Description: Returns true if the collision entry knows how "deep"
 //               the collision was from the collided-from object; that
 //               the collision was from the collided-from object; that
 //               is, how far from the surface of the collided-from
 //               is, how far from the surface of the collided-from
@@ -400,7 +452,7 @@ has_from_depth() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionEntry::get_from_depth
 //     Function: CollisionEntry::get_from_depth
-//       Access: Public
+//       Access: Published
 //  Description: Returns how "deep" the collision was from the
 //  Description: Returns how "deep" the collision was from the
 //               collided-from object; that is, how far from the
 //               collided-from object; that is, how far from the
 //               surface of the collided-from object the colliding
 //               surface of the collided-from object the colliding

+ 3 - 1
panda/src/collide/collisionEntry.cxx

@@ -37,6 +37,7 @@ CollisionEntry(const CollisionEntry &copy) :
   _wrt_space(copy._wrt_space),
   _wrt_space(copy._wrt_space),
   _inv_wrt_space(copy._inv_wrt_space),
   _inv_wrt_space(copy._inv_wrt_space),
   _flags(copy._flags),
   _flags(copy._flags),
+  _from_pos_delta(copy._from_pos_delta),
   _into_intersection_point(copy._into_intersection_point),
   _into_intersection_point(copy._into_intersection_point),
   _into_surface_normal(copy._into_surface_normal),
   _into_surface_normal(copy._into_surface_normal),
   _into_depth(copy._into_depth)
   _into_depth(copy._into_depth)
@@ -60,6 +61,7 @@ operator = (const CollisionEntry &copy) {
   _wrt_space = copy._wrt_space;
   _wrt_space = copy._wrt_space;
   _inv_wrt_space = copy._inv_wrt_space;
   _inv_wrt_space = copy._inv_wrt_space;
   _flags = copy._flags;
   _flags = copy._flags;
+  _from_pos_delta = copy._from_pos_delta;
   _into_intersection_point = copy._into_intersection_point;
   _into_intersection_point = copy._into_intersection_point;
   _into_surface_normal = copy._into_surface_normal;
   _into_surface_normal = copy._into_surface_normal;
   _into_depth = copy._into_depth;
   _into_depth = copy._into_depth;
@@ -74,6 +76,6 @@ operator = (const CollisionEntry &copy) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CollisionEntry::
 void CollisionEntry::
 compute_from_surface_normal() {
 compute_from_surface_normal() {
-  _from_surface_normal = get_into_surface_normal() * get_inv_wrt_space();
+  _from_surface_normal = get_into_surface_normal() * get_inv_wrt_mat();
   _flags |= F_has_from_surface_normal;
   _flags |= F_has_from_surface_normal;
 }
 }

+ 19 - 13
panda/src/collide/collisionEntry.h

@@ -26,6 +26,7 @@
 #include "collisionNode.h"
 #include "collisionNode.h"
 #include "collisionRecorder.h"
 #include "collisionRecorder.h"
 
 
+#include "transformState.h"
 #include "typedReferenceCount.h"
 #include "typedReferenceCount.h"
 #include "luse.h"
 #include "luse.h"
 #include "pointerTo.h"
 #include "pointerTo.h"
@@ -60,14 +61,19 @@ PUBLISHED:
   INLINE PandaNode *get_into_node() const;
   INLINE PandaNode *get_into_node() const;
   INLINE const NodePath &get_into_node_path() const;
   INLINE const NodePath &get_into_node_path() const;
 
 
-  INLINE const LMatrix4f &get_from_space() const;
-  INLINE const LMatrix4f &get_into_space() const;
-  INLINE const LMatrix4f &get_wrt_space() const;
-  INLINE const LMatrix4f &get_inv_wrt_space() const;
+  INLINE const TransformState *get_from_space() const;
+  INLINE const TransformState *get_into_space() const;
+  INLINE const TransformState *get_wrt_space() const;
+  INLINE const TransformState *get_inv_wrt_space() const;
 
 
-  INLINE void set_from_velocity(const LVector3f &vel);
-  INLINE bool has_from_velocity() const;
-  INLINE const LVector3f &get_from_velocity() const;
+  INLINE const LMatrix4f &get_from_mat() const;
+  INLINE const LMatrix4f &get_into_mat() const;
+  INLINE const LMatrix4f &get_wrt_mat() const;
+  INLINE const LMatrix4f &get_inv_wrt_mat() const;
+
+  INLINE void set_from_pos_delta(const LVector3f &vel);
+  INLINE bool has_from_pos_delta() const;
+  INLINE const LVector3f &get_from_pos_delta() const;
 
 
   INLINE void set_into_intersection_point(const LPoint3f &point);
   INLINE void set_into_intersection_point(const LPoint3f &point);
   INLINE bool has_into_intersection_point() const;
   INLINE bool has_into_intersection_point() const;
@@ -103,10 +109,10 @@ private:
   PT(CollisionNode) _from_node;
   PT(CollisionNode) _from_node;
   PT(PandaNode) _into_node;
   PT(PandaNode) _into_node;
   NodePath _into_node_path;
   NodePath _into_node_path;
-  LMatrix4f _from_space;
-  LMatrix4f _into_space;
-  LMatrix4f _wrt_space;
-  LMatrix4f _inv_wrt_space;
+  CPT(TransformState) _from_space;
+  CPT(TransformState) _into_space;
+  CPT(TransformState) _wrt_space;
+  CPT(TransformState) _inv_wrt_space;
 
 
   enum Flags {
   enum Flags {
     F_has_into_intersection_point = 0x0001,
     F_has_into_intersection_point = 0x0001,
@@ -114,12 +120,12 @@ private:
     F_has_from_surface_normal     = 0x0004,
     F_has_from_surface_normal     = 0x0004,
     F_has_into_depth              = 0x0008,
     F_has_into_depth              = 0x0008,
     F_has_from_depth              = 0x0010,
     F_has_from_depth              = 0x0010,
-    F_has_from_velocity           = 0x0020,
+    F_has_from_pos_delta          = 0x0020,
   };
   };
 
 
   int _flags;
   int _flags;
 
 
-  LVector3f _from_velocity;
+  LVector3f _from_pos_delta;
   LPoint3f _into_intersection_point;
   LPoint3f _into_intersection_point;
   LVector3f _into_surface_normal;
   LVector3f _into_surface_normal;
   LVector3f _from_surface_normal;
   LVector3f _from_surface_normal;

+ 1 - 0
panda/src/collide/collisionHandlerFloor.cxx

@@ -133,6 +133,7 @@ handle_entries() {
             LVecBase3f pos = trans->get_pos();
             LVecBase3f pos = trans->get_pos();
             pos[2] += adjust;
             pos[2] += adjust;
             def._node->set_transform(trans->set_pos(pos));
             def._node->set_transform(trans->set_pos(pos));
+
           } else {
           } else {
             // Otherwise, go ahead and do the matrix math to do things
             // Otherwise, go ahead and do the matrix math to do things
             // the old and clumsy way.
             // the old and clumsy way.

+ 32 - 6
panda/src/collide/collisionLevelState.I

@@ -167,10 +167,10 @@ get_node(int n) const {
 //       Access: Public
 //       Access: Public
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE const LMatrix4f &CollisionLevelState::
+INLINE const TransformState *CollisionLevelState::
 get_space(int n) const {
 get_space(int n) const {
-  nassertr(n >= 0 && n < (int)_colliders.size(), LMatrix4f::ident_mat());
-  nassertr(has_collider(n), LMatrix4f::ident_mat());
+  nassertr(n >= 0 && n < (int)_colliders.size(), TransformState::make_identity());
+  nassertr(has_collider(n), TransformState::make_identity());
 
 
   return _colliders[n]._space;
   return _colliders[n]._space;
 }
 }
@@ -180,14 +180,40 @@ get_space(int n) const {
 //       Access: Public
 //       Access: Public
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE const LMatrix4f &CollisionLevelState::
+INLINE const TransformState *CollisionLevelState::
 get_inv_space(int n) const {
 get_inv_space(int n) const {
-  nassertr(n >= 0 && n < (int)_colliders.size(), LMatrix4f::ident_mat());
-  nassertr(has_collider(n), LMatrix4f::ident_mat());
+  nassertr(n >= 0 && n < (int)_colliders.size(), TransformState::make_identity());
+  nassertr(has_collider(n), TransformState::make_identity());
 
 
   return _colliders[n]._inv_space;
   return _colliders[n]._inv_space;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: CollisionLevelState::get_prev_space
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE const TransformState *CollisionLevelState::
+get_prev_space(int n) const {
+  nassertr(n >= 0 && n < (int)_colliders.size(), TransformState::make_identity());
+  nassertr(has_collider(n), TransformState::make_identity());
+
+  return _colliders[n]._prev_space;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CollisionLevelState::get_delta
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE const LVector3f &CollisionLevelState::
+get_delta(int n) const {
+  nassertr(n >= 0 && n < (int)_colliders.size(), LVector3f::zero());
+  nassertr(has_collider(n), LVector3f::zero());
+
+  return _colliders[n]._delta;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionLevelState::get_local_bound
 //     Function: CollisionLevelState::get_local_bound
 //       Access: Public
 //       Access: Public

+ 5 - 5
panda/src/collide/collisionLevelState.cxx

@@ -64,20 +64,20 @@ prepare_collider(const ColliderDef &def) {
     GeometricBoundingVolume *gbv;
     GeometricBoundingVolume *gbv;
     DCAST_INTO_V(gbv, bv.make_copy());
     DCAST_INTO_V(gbv, bv.make_copy());
 
 
-    if (def._node->has_velocity()) {
-      // If the node has a velocity, we have to include the starting
+    if (def._delta != LVector3f::zero()) {
+      // If the node has a delta, we have to include the starting
       // point in the volume as well.
       // point in the volume as well.
 
 
       // Strictly speaking, we should actually transform gbv backward
       // Strictly speaking, we should actually transform gbv backward
-      // by get_velocity(), and extend by *that* volume, instead of
+      // by the delta(), and extend by *that* volume, instead of
       // just extending by the single point at -get_velocity().
       // just extending by the single point at -get_velocity().
       // However, assuming the solids within a moving CollisionNode
       // However, assuming the solids within a moving CollisionNode
       // tend to be near the origin, this will generally produce the
       // tend to be near the origin, this will generally produce the
       // same results, and is much easier to compute.
       // same results, and is much easier to compute.
-      gbv->extend_by(LPoint3f(-def._node->get_velocity()));
+      gbv->extend_by(LPoint3f(-def._delta));
     }
     }
 
 
-    gbv->xform(def._space);
+    gbv->xform(def._space->get_mat());
     _local_bounds.push_back(gbv);
     _local_bounds.push_back(gbv);
   }
   }
 
 

+ 10 - 5
panda/src/collide/collisionLevelState.h

@@ -26,7 +26,8 @@
 #include "geometricBoundingVolume.h"
 #include "geometricBoundingVolume.h"
 #include "nodePath.h"
 #include "nodePath.h"
 #include "workingNodePath.h"
 #include "workingNodePath.h"
-
+#include "transformState.h"
+#include "pointerTo.h"
 #include "plist.h"
 #include "plist.h"
 
 
 class CollisionSolid;
 class CollisionSolid;
@@ -44,8 +45,10 @@ public:
   public:
   public:
     CollisionSolid *_collider;
     CollisionSolid *_collider;
     CollisionNode *_node;
     CollisionNode *_node;
-    LMatrix4f _space;
-    LMatrix4f _inv_space;
+    CPT(TransformState) _space;
+    CPT(TransformState) _inv_space;
+    CPT(TransformState) _prev_space;
+    LVector3f _delta;
   };
   };
 
 
   INLINE CollisionLevelState(const NodePath &node_path);
   INLINE CollisionLevelState(const NodePath &node_path);
@@ -72,8 +75,10 @@ public:
 
 
   INLINE CollisionSolid *get_collider(int n) const;
   INLINE CollisionSolid *get_collider(int n) const;
   INLINE CollisionNode *get_node(int n) const;
   INLINE CollisionNode *get_node(int n) const;
-  INLINE const LMatrix4f &get_space(int n) const;
-  INLINE const LMatrix4f &get_inv_space(int n) const;
+  INLINE const TransformState *get_space(int n) const;
+  INLINE const TransformState *get_inv_space(int n) const;
+  INLINE const TransformState *get_prev_space(int n) const;
+  INLINE const LVector3f &get_delta(int n) const;
   INLINE const GeometricBoundingVolume *get_local_bound(int n) const;
   INLINE const GeometricBoundingVolume *get_local_bound(int n) const;
   INLINE const GeometricBoundingVolume *get_parent_bound(int n) const;
   INLINE const GeometricBoundingVolume *get_parent_bound(int n) const;
 
 

+ 7 - 2
panda/src/collide/collisionNode.cxx

@@ -216,10 +216,15 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
     trav->traverse(next_data);
     trav->traverse(next_data);
   }
   }
 
 
-  if (has_velocity()) {
+  // Determine the previous frame's position, relative to the
+  // current position.
+  NodePath node_path = data._node_path.get_node_path();
+  CPT(TransformState) transform = node_path.get_net_transform()->invert_compose(node_path.get_net_prev_transform());
+  
+  if (!transform->is_identity()) {
     // If we have a velocity, also draw the previous frame's position,
     // If we have a velocity, also draw the previous frame's position,
     // ghosted.
     // ghosted.
-    CPT(TransformState) transform = TransformState::make_pos(-get_velocity());
+
     for (si = _solids.begin(); si != _solids.end(); ++si) {
     for (si = _solids.begin(); si != _solids.end(); ++si) {
       CollisionSolid *solid = (*si);
       CollisionSolid *solid = (*si);
       PandaNode *node = solid->get_viz();
       PandaNode *node = solid->get_viz();

+ 5 - 5
panda/src/collide/collisionPlane.cxx

@@ -108,9 +108,9 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
   const CollisionSphere *sphere;
   const CollisionSphere *sphere;
   DCAST_INTO_R(sphere, entry.get_from(), 0);
   DCAST_INTO_R(sphere, entry.get_from(), 0);
 
 
-  LPoint3f from_center = sphere->get_center() * entry.get_wrt_space();
+  LPoint3f from_center = sphere->get_center() * entry.get_wrt_mat();
   LVector3f from_radius_v =
   LVector3f from_radius_v =
-    LVector3f(sphere->get_radius(), 0.0f, 0.0f) * entry.get_wrt_space();
+    LVector3f(sphere->get_radius(), 0.0f, 0.0f) * entry.get_wrt_mat();
   float from_radius = length(from_radius_v);
   float from_radius = length(from_radius_v);
 
 
   float dist = dist_to_plane(from_center);
   float dist = dist_to_plane(from_center);
@@ -126,7 +126,7 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
   }
   }
   PT(CollisionEntry) new_entry = new CollisionEntry(entry);
   PT(CollisionEntry) new_entry = new CollisionEntry(entry);
 
 
-  LVector3f from_normal = get_normal() * entry.get_inv_wrt_space();
+  LVector3f from_normal = get_normal() * entry.get_inv_wrt_mat();
   float from_depth = from_radius - dist;
   float from_depth = from_radius - dist;
 
 
   new_entry->set_into_surface_normal(get_normal());
   new_entry->set_into_surface_normal(get_normal());
@@ -147,8 +147,8 @@ test_intersection_from_ray(const CollisionEntry &entry) const {
   const CollisionRay *ray;
   const CollisionRay *ray;
   DCAST_INTO_R(ray, entry.get_from(), 0);
   DCAST_INTO_R(ray, entry.get_from(), 0);
 
 
-  LPoint3f from_origin = ray->get_origin() * entry.get_wrt_space();
-  LVector3f from_direction = ray->get_direction() * entry.get_wrt_space();
+  LPoint3f from_origin = ray->get_origin() * entry.get_wrt_mat();
+  LVector3f from_direction = ray->get_direction() * entry.get_wrt_mat();
 
 
   float t;
   float t;
   if (!_plane.intersects_line(t, from_origin, from_direction)) {
   if (!_plane.intersects_line(t, from_origin, from_direction)) {

+ 11 - 11
panda/src/collide/collisionPolygon.cxx

@@ -273,15 +273,15 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
   const CollisionSphere *sphere;
   const CollisionSphere *sphere;
   DCAST_INTO_R(sphere, entry.get_from(), 0);
   DCAST_INTO_R(sphere, entry.get_from(), 0);
 
 
-  LPoint3f orig_center = sphere->get_center() * entry.get_wrt_space();
+  LPoint3f orig_center = sphere->get_center() * entry.get_wrt_mat();
   LPoint3f from_center = orig_center;
   LPoint3f from_center = orig_center;
   bool moved_from_center = false;
   bool moved_from_center = false;
 
 
-  if (entry.has_from_velocity()) {
-    // If we have a velocity indication, we use that to determine some
+  if (entry.has_from_pos_delta()) {
+    // If we have a pos_delta indication, we use that to determine some
     // more properties of the collision.
     // more properties of the collision.
     LPoint3f b = from_center;
     LPoint3f b = from_center;
-    LPoint3f a = (sphere->get_center() - entry.get_from_velocity()) * entry.get_wrt_space();
+    LPoint3f a = (sphere->get_center() - entry.get_from_pos_delta()) * entry.get_wrt_mat();
 
 
     LVector3f delta = b - a;
     LVector3f delta = b - a;
     // First, there is no collision if the "from" object is moving in
     // First, there is no collision if the "from" object is moving in
@@ -316,7 +316,7 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
   }
   }
 
 
   LVector3f from_radius_v =
   LVector3f from_radius_v =
-    LVector3f(sphere->get_radius(), 0.0f, 0.0f) * entry.get_wrt_space();
+    LVector3f(sphere->get_radius(), 0.0f, 0.0f) * entry.get_wrt_mat();
   float from_radius = length(from_radius_v);
   float from_radius = length(from_radius_v);
 
 
   float dist = dist_to_plane(from_center);
   float dist = dist_to_plane(from_center);
@@ -408,8 +408,8 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
   new_entry->set_into_surface_normal(get_normal());
   new_entry->set_into_surface_normal(get_normal());
   new_entry->set_into_depth(into_depth);
   new_entry->set_into_depth(into_depth);
 
 
-  LVector3f from_normal = get_normal() * entry.get_inv_wrt_space();
-  LVector3f from_depth_vec = (get_normal() * into_depth) * entry.get_inv_wrt_space();
+  LVector3f from_normal = get_normal() * entry.get_inv_wrt_mat();
+  LVector3f from_depth_vec = (get_normal() * into_depth) * entry.get_inv_wrt_mat();
   new_entry->set_from_surface_normal(from_normal);
   new_entry->set_from_surface_normal(from_normal);
   new_entry->set_from_depth(from_depth_vec.length());
   new_entry->set_from_depth(from_depth_vec.length());
 
 
@@ -434,8 +434,8 @@ test_intersection_from_ray(const CollisionEntry &entry) const {
   const CollisionRay *ray;
   const CollisionRay *ray;
   DCAST_INTO_R(ray, entry.get_from(), 0);
   DCAST_INTO_R(ray, entry.get_from(), 0);
 
 
-  LPoint3f from_origin = ray->get_origin() * entry.get_wrt_space();
-  LVector3f from_direction = ray->get_direction() * entry.get_wrt_space();
+  LPoint3f from_origin = ray->get_origin() * entry.get_wrt_mat();
+  LVector3f from_direction = ray->get_direction() * entry.get_wrt_mat();
 
 
   float t;
   float t;
   if (!get_plane().intersects_line(t, from_origin, from_direction)) {
   if (!get_plane().intersects_line(t, from_origin, from_direction)) {
@@ -483,8 +483,8 @@ test_intersection_from_segment(const CollisionEntry &entry) const {
   const CollisionSegment *segment;
   const CollisionSegment *segment;
   DCAST_INTO_R(segment, entry.get_from(), 0);
   DCAST_INTO_R(segment, entry.get_from(), 0);
 
 
-  LPoint3f from_a = segment->get_point_a() * entry.get_wrt_space();
-  LPoint3f from_b = segment->get_point_b() * entry.get_wrt_space();
+  LPoint3f from_a = segment->get_point_a() * entry.get_wrt_mat();
+  LPoint3f from_b = segment->get_point_b() * entry.get_wrt_mat();
   LPoint3f from_direction = from_b - from_a;
   LPoint3f from_direction = from_b - from_a;
 
 
   float t;
   float t;

+ 7 - 7
panda/src/collide/collisionSphere.cxx

@@ -121,9 +121,9 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
   const CollisionSphere *sphere;
   const CollisionSphere *sphere;
   DCAST_INTO_R(sphere, entry.get_from(), 0);
   DCAST_INTO_R(sphere, entry.get_from(), 0);
 
 
-  LPoint3f from_center = sphere->get_center() * entry.get_wrt_space();
+  LPoint3f from_center = sphere->get_center() * entry.get_wrt_mat();
   LVector3f from_radius_v =
   LVector3f from_radius_v =
-    LVector3f(sphere->get_radius(), 0.0f, 0.0f) * entry.get_wrt_space();
+    LVector3f(sphere->get_radius(), 0.0f, 0.0f) * entry.get_wrt_mat();
   float from_radius = length(from_radius_v);
   float from_radius = length(from_radius_v);
 
 
   LPoint3f into_center = _center;
   LPoint3f into_center = _center;
@@ -161,7 +161,7 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
   new_entry->set_into_intersection_point(into_intersection_point);
   new_entry->set_into_intersection_point(into_intersection_point);
   new_entry->set_into_depth(into_depth);
   new_entry->set_into_depth(into_depth);
 
 
-  LVector3f from_depth_vec = (into_normal * into_depth) * entry.get_inv_wrt_space();
+  LVector3f from_depth_vec = (into_normal * into_depth) * entry.get_inv_wrt_mat();
   new_entry->set_from_depth(from_depth_vec.length());
   new_entry->set_from_depth(from_depth_vec.length());
 
 
   return new_entry;
   return new_entry;
@@ -177,8 +177,8 @@ test_intersection_from_ray(const CollisionEntry &entry) const {
   const CollisionRay *ray;
   const CollisionRay *ray;
   DCAST_INTO_R(ray, entry.get_from(), 0);
   DCAST_INTO_R(ray, entry.get_from(), 0);
 
 
-  LPoint3f from_origin = ray->get_origin() * entry.get_wrt_space();
-  LVector3f from_direction = ray->get_direction() * entry.get_wrt_space();
+  LPoint3f from_origin = ray->get_origin() * entry.get_wrt_mat();
+  LVector3f from_direction = ray->get_direction() * entry.get_wrt_mat();
 
 
   double t1, t2;
   double t1, t2;
   if (!intersects_line(t1, t2, from_origin, from_direction)) {
   if (!intersects_line(t1, t2, from_origin, from_direction)) {
@@ -223,8 +223,8 @@ test_intersection_from_segment(const CollisionEntry &entry) const {
   const CollisionSegment *segment;
   const CollisionSegment *segment;
   DCAST_INTO_R(segment, entry.get_from(), 0);
   DCAST_INTO_R(segment, entry.get_from(), 0);
 
 
-  LPoint3f from_a = segment->get_point_a() * entry.get_wrt_space();
-  LPoint3f from_b = segment->get_point_b() * entry.get_wrt_space();
+  LPoint3f from_a = segment->get_point_a() * entry.get_wrt_mat();
+  LPoint3f from_b = segment->get_point_b() * entry.get_wrt_mat();
   LVector3f from_direction = from_b - from_a;
   LVector3f from_direction = from_b - from_a;
 
 
   double t1, t2;
   double t1, t2;

+ 30 - 0
panda/src/collide/collisionTraverser.I

@@ -17,6 +17,36 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: CollisionTraverser::set_respect_prev_transform
+//       Access: Public
+//  Description: Sets the flag that indicates whether the
+//               prev_transform stored on a node (as updated via
+//               set_fluid_pos(), etc.) is respected to calculate
+//               collisions.  If this is true, certain types of
+//               collision tests will be enhanced by the information
+//               about objects in motion.  If this is false, objects
+//               are always considered to be static.  The default is
+//               false.
+////////////////////////////////////////////////////////////////////
+INLINE void CollisionTraverser::
+set_respect_prev_transform(bool flag) {
+  _respect_prev_transform = flag;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CollisionTraverser::get_respect_prev_transform
+//       Access: Public
+//  Description: Returns the flag that indicates whether the
+//               prev_transform stored on a node is respected to
+//               calculate collisions.  See
+//               set_respect_prev_transform().
+////////////////////////////////////////////////////////////////////
+INLINE bool CollisionTraverser::
+get_respect_prev_transform() const {
+  return _respect_prev_transform;
+}
+
 #ifdef DO_COLLISION_RECORDING
 #ifdef DO_COLLISION_RECORDING
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 63 - 39
panda/src/collide/collisionTraverser.cxx

@@ -41,6 +41,7 @@ PStatCollector CollisionTraverser::_collisions_pcollector("App:Collisions");
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CollisionTraverser::
 CollisionTraverser::
 CollisionTraverser() {
 CollisionTraverser() {
+  _respect_prev_transform = false;
 #ifdef DO_COLLISION_RECORDING
 #ifdef DO_COLLISION_RECORDING
   _recorder = (CollisionRecorder *)NULL;
   _recorder = (CollisionRecorder *)NULL;
 #endif
 #endif
@@ -262,17 +263,6 @@ traverse(const NodePath &root) {
     }
     }
   }
   }
 
 
-  if (auto_clear_velocity) {
-    // Clear all the velocities for next time.
-    OrderedColliders::iterator ci;
-    for (ci = _ordered_colliders.begin(); 
-         ci != _ordered_colliders.end(); 
-         ++ci) {
-      CollisionNode *node = (*ci);
-      node->clear_velocity();
-    }
-  }
-
 #ifdef DO_COLLISION_RECORDING
 #ifdef DO_COLLISION_RECORDING
   if (has_recorder()) {
   if (has_recorder()) {
     get_recorder()->end_traversal();
     get_recorder()->end_traversal();
@@ -280,6 +270,20 @@ traverse(const NodePath &root) {
 #endif  // DO_COLLISION_RECORDING
 #endif  // DO_COLLISION_RECORDING
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: CollisionTraverser::reset_prev_transform
+//       Access: Public
+//  Description: Once the collision traversal has finished, resets all
+//               of the velocity deltas in the scene graph by setting
+//               the "previous" transform to the current transform.
+//               This must be called at least once per frame for
+//               collisions to respect this velocity setting properly.
+////////////////////////////////////////////////////////////////////
+void CollisionTraverser::
+reset_prev_transform(const NodePath &root) {
+  r_reset_prev_transform(root.node());
+}
+
 #ifdef DO_COLLISION_RECORDING
 #ifdef DO_COLLISION_RECORDING
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionTraverser::set_recorder
 //     Function: CollisionTraverser::set_recorder
@@ -381,16 +385,22 @@ prepare_colliders(CollisionLevelState &level_state) {
 
 
     CollisionLevelState::ColliderDef def;
     CollisionLevelState::ColliderDef def;
     def._node = cnode;
     def._node = cnode;
-    NodePath root;
     NodePath cnode_path(cnode);
     NodePath cnode_path(cnode);
-    def._space = cnode_path.get_mat(root);
-    def._inv_space = root.get_mat(cnode_path);
+    def._space = cnode_path.get_net_transform();
+    def._inv_space = def._space->invert_compose(TransformState::make_identity());
+    def._prev_space = cnode_path.get_net_prev_transform();
+    if (_respect_prev_transform) {
+      def._delta = cnode_path.get_pos_delta();
+    } else {
+      def._delta = LVector3f::zero();
+    }
+
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
-    if (def._space.is_nan()) {
+    if (def._space->is_invalid()) {
       collide_cat.error()
       collide_cat.error()
         << "Collider " << *cnode
         << "Collider " << *cnode
-        << " has become NaN.  Dropping from traverser.\n";
+        << " has become invalid.  Dropping from traverser.\n";
       // This is safe to do while traversing the list of colliders,
       // This is safe to do while traversing the list of colliders,
       // because we do not increment i in this case.
       // because we do not increment i in this case.
       remove_collider(cnode);
       remove_collider(cnode);
@@ -435,7 +445,7 @@ r_traverse(CollisionLevelState &level_state) {
     CollisionEntry entry;
     CollisionEntry entry;
     entry._into_node = cnode;
     entry._into_node = cnode;
     entry._into_node_path = level_state.get_node_path();
     entry._into_node_path = level_state.get_node_path();
-    entry._into_space = entry._into_node_path.get_mat(NodePath());
+    entry._into_space = entry._into_node_path.get_net_transform();
 
 
     int num_colliders = level_state.get_num_colliders();
     int num_colliders = level_state.get_num_colliders();
     for (int c = 0; c < num_colliders; c++) {
     for (int c = 0; c < num_colliders; c++) {
@@ -447,17 +457,27 @@ r_traverse(CollisionLevelState &level_state) {
           entry._from = level_state.get_collider(c);
           entry._from = level_state.get_collider(c);
           entry._from_space = level_state.get_space(c);
           entry._from_space = level_state.get_space(c);
 
 
-          if (entry._from_node->has_velocity()) {
-            entry.set_from_velocity(entry._from_node->get_velocity());
+          LVector3f from_delta = level_state.get_delta(c);
+
+          entry._wrt_space = entry._into_space->invert_compose(entry._from_space);
+          entry._inv_wrt_space = entry._from_space->invert_compose(entry._into_space);
+          if (_respect_prev_transform) {
+            CPT(TransformState) from_prev_space = level_state.get_prev_space(c);
+            CPT(TransformState) inv_wrt_prev_space = from_prev_space->invert_compose(entry._into_node_path.get_net_prev_transform());
+            
+            LVector3f into_delta = entry._inv_wrt_space->get_pos() - inv_wrt_prev_space->get_pos();
+            LVector3f delta = from_delta - into_delta;
+            if (delta != LVector3f::zero()) {
+              /*
+                if (entry._from_node->get_name() == "cSphereNode" && entry._into_node->get_name() == "MickeyBlatherSphere") {
+                cerr << "from_delta = " << from_delta << " into_delta = "
+                << into_delta << " delta = " << delta << "\n";
+                }
+              */
+              entry.set_from_pos_delta(delta);
+            }
           }
           }
 
 
-          NodePath root;
-          const LMatrix4f &into_space_inv = 
-            root.get_mat(entry._into_node_path);
-          entry._wrt_space = entry._from_space * into_space_inv;
-          entry._inv_wrt_space =
-            entry._into_space * level_state.get_inv_space(c);
-
           compare_collider_to_node(entry, 
           compare_collider_to_node(entry, 
                                    level_state.get_parent_bound(c),
                                    level_state.get_parent_bound(c),
                                    level_state.get_local_bound(c),
                                    level_state.get_local_bound(c),
@@ -485,7 +505,7 @@ r_traverse(CollisionLevelState &level_state) {
     CollisionEntry entry;
     CollisionEntry entry;
     entry._into_node = gnode;
     entry._into_node = gnode;
     entry._into_node_path = level_state.get_node_path();
     entry._into_node_path = level_state.get_node_path();
-    entry._into_space = entry._into_node_path.get_mat(NodePath());
+    entry._into_space = entry._into_node_path.get_net_transform();
 
 
     int num_colliders = level_state.get_num_colliders();
     int num_colliders = level_state.get_num_colliders();
     for (int c = 0; c < num_colliders; c++) {
     for (int c = 0; c < num_colliders; c++) {
@@ -495,12 +515,8 @@ r_traverse(CollisionLevelState &level_state) {
         entry._from = level_state.get_collider(c);
         entry._from = level_state.get_collider(c);
         entry._from_space = level_state.get_space(c);
         entry._from_space = level_state.get_space(c);
 
 
-        NodePath root;
-        const LMatrix4f &into_space_inv = 
-          root.get_mat(entry._into_node_path);
-        entry._wrt_space = entry._from_space * into_space_inv;
-        entry._inv_wrt_space =
-          entry._into_space * level_state.get_inv_space(c);
+        entry._wrt_space = entry._into_space->invert_compose(entry._from_space);
+        entry._inv_wrt_space = entry._from_space->invert_compose(entry._into_space);
 
 
         compare_collider_to_geom_node(entry, 
         compare_collider_to_geom_node(entry, 
                                       level_state.get_parent_bound(c),
                                       level_state.get_parent_bound(c),
@@ -716,12 +732,6 @@ remove_handler(CollisionTraverser::Handlers::iterator hi) {
       
       
       nassertr(_ordered_colliders.size() == _colliders.size(), false);
       nassertr(_ordered_colliders.size() == _colliders.size(), false);
 
 
-      if (auto_clear_velocity) {
-        // Clear the velocity on the removed node, to be consistent
-        // with nodes that were not removed.
-        node->clear_velocity();
-      }
-
     } else {
     } else {
       // This collider references some other handler; keep it.
       // This collider references some other handler; keep it.
       ++ci;
       ++ci;
@@ -730,3 +740,17 @@ remove_handler(CollisionTraverser::Handlers::iterator hi) {
 
 
   return hi;
   return hi;
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: CollisionTraverser::r_reset_prev_transform
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void CollisionTraverser::
+r_reset_prev_transform(PandaNode *node) {
+  node->reset_prev_transform();
+  int num_children = node->get_num_children();
+  for (int i = 0; i < num_children; i++) {
+    r_reset_prev_transform(node->get_child(i));
+  }
+}

+ 7 - 0
panda/src/collide/collisionTraverser.h

@@ -53,6 +53,9 @@ PUBLISHED:
   CollisionTraverser();
   CollisionTraverser();
   ~CollisionTraverser();
   ~CollisionTraverser();
 
 
+  INLINE void set_respect_prev_transform(bool flag);
+  INLINE bool get_respect_prev_transform() const;
+
   void add_collider(CollisionNode *node, CollisionHandler *handler);
   void add_collider(CollisionNode *node, CollisionHandler *handler);
   bool remove_collider(CollisionNode *node);
   bool remove_collider(CollisionNode *node);
   bool has_collider(CollisionNode *node) const;
   bool has_collider(CollisionNode *node) const;
@@ -62,6 +65,7 @@ PUBLISHED:
   void clear_colliders();
   void clear_colliders();
 
 
   void traverse(const NodePath &root);
   void traverse(const NodePath &root);
+  void reset_prev_transform(const NodePath &root);
 
 
 #ifdef DO_COLLISION_RECORDING
 #ifdef DO_COLLISION_RECORDING
   void set_recorder(CollisionRecorder *recorder);
   void set_recorder(CollisionRecorder *recorder);
@@ -93,6 +97,8 @@ private:
                                 const GeometricBoundingVolume *from_node_gbv,
                                 const GeometricBoundingVolume *from_node_gbv,
                                 const GeometricBoundingVolume *solid_gbv);
                                 const GeometricBoundingVolume *solid_gbv);
 
 
+  void r_reset_prev_transform(PandaNode *node);
+
 private:
 private:
   PT(CollisionHandler) _default_handler;
   PT(CollisionHandler) _default_handler;
   TypeHandle _graph_type;
   TypeHandle _graph_type;
@@ -107,6 +113,7 @@ private:
 
 
   Handlers::iterator remove_handler(Handlers::iterator hi);
   Handlers::iterator remove_handler(Handlers::iterator hi);
 
 
+  bool _respect_prev_transform;
 #ifdef DO_COLLISION_RECORDING
 #ifdef DO_COLLISION_RECORDING
   CollisionRecorder *_recorder;
   CollisionRecorder *_recorder;
 #endif  // DO_COLLISION_RECORDING
 #endif  // DO_COLLISION_RECORDING

+ 9 - 9
panda/src/collide/collisionTube.cxx

@@ -130,17 +130,17 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
   const CollisionSphere *sphere;
   const CollisionSphere *sphere;
   DCAST_INTO_R(sphere, entry.get_from(), 0);
   DCAST_INTO_R(sphere, entry.get_from(), 0);
 
 
-  LPoint3f from_a = sphere->get_center() * entry.get_wrt_space();
+  LPoint3f from_a = sphere->get_center() * entry.get_wrt_mat();
   LPoint3f from_b = from_a;
   LPoint3f from_b = from_a;
 
 
-  if (entry.has_from_velocity()) {
-    from_a = (sphere->get_center() - entry.get_from_velocity()) * entry.get_wrt_space();
+  if (entry.has_from_pos_delta()) {
+    from_a = (sphere->get_center() - entry.get_from_pos_delta()) * entry.get_wrt_mat();
   }
   }
 
 
   LVector3f from_direction = from_b - from_a;
   LVector3f from_direction = from_b - from_a;
 
 
   LVector3f from_radius_v =
   LVector3f from_radius_v =
-    LVector3f(sphere->get_radius(), 0.0f, 0.0f) * entry.get_wrt_space();
+    LVector3f(sphere->get_radius(), 0.0f, 0.0f) * entry.get_wrt_mat();
   float from_radius = length(from_radius_v);
   float from_radius = length(from_radius_v);
 
 
   double t1, t2;
   double t1, t2;
@@ -187,8 +187,8 @@ test_intersection_from_ray(const CollisionEntry &entry) const {
   const CollisionRay *ray;
   const CollisionRay *ray;
   DCAST_INTO_R(ray, entry.get_from(), 0);
   DCAST_INTO_R(ray, entry.get_from(), 0);
 
 
-  LPoint3f from_origin = ray->get_origin() * entry.get_wrt_space();
-  LVector3f from_direction = ray->get_direction() * entry.get_wrt_space();
+  LPoint3f from_origin = ray->get_origin() * entry.get_wrt_mat();
+  LVector3f from_direction = ray->get_direction() * entry.get_wrt_mat();
 
 
   double t1, t2;
   double t1, t2;
   if (!intersects_line(t1, t2, from_origin, from_direction, 0.0f)) {
   if (!intersects_line(t1, t2, from_origin, from_direction, 0.0f)) {
@@ -233,8 +233,8 @@ test_intersection_from_segment(const CollisionEntry &entry) const {
   const CollisionSegment *segment;
   const CollisionSegment *segment;
   DCAST_INTO_R(segment, entry.get_from(), 0);
   DCAST_INTO_R(segment, entry.get_from(), 0);
 
 
-  LPoint3f from_a = segment->get_point_a() * entry.get_wrt_space();
-  LPoint3f from_b = segment->get_point_b() * entry.get_wrt_space();
+  LPoint3f from_a = segment->get_point_a() * entry.get_wrt_mat();
+  LPoint3f from_b = segment->get_point_b() * entry.get_wrt_mat();
   LVector3f from_direction = from_b - from_a;
   LVector3f from_direction = from_b - from_a;
 
 
   double t1, t2;
   double t1, t2;
@@ -689,7 +689,7 @@ set_intersection_point(CollisionEntry *new_entry,
   new_entry->set_into_surface_normal(normal);
   new_entry->set_into_surface_normal(normal);
   new_entry->set_into_depth(depth);
   new_entry->set_into_depth(depth);
 
 
-  LVector3f from_depth_vec = (normal * depth) * new_entry->get_inv_wrt_space();
+  LVector3f from_depth_vec = (normal * depth) * new_entry->get_inv_wrt_mat();
   new_entry->set_from_depth(from_depth_vec.length());
   new_entry->set_from_depth(from_depth_vec.length());
 }
 }
 
 

+ 0 - 5
panda/src/collide/config_collide.cxx

@@ -43,11 +43,6 @@ ConfigureFn(config_collide) {
   init_libcollide();
   init_libcollide();
 }
 }
 
 
-// Set this false to stop the CollisionTraverser from automatically
-// clearing the velocity associated with its CollisionNodes after it
-// has traversed them.  Mainly useful for visualizing the velocities.
-const bool auto_clear_velocity = config_collide.GetBool("auto-clear-velocity", true);
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: init_libcollide
 //     Function: init_libcollide
 //  Description: Initializes the library.  This must be called at
 //  Description: Initializes the library.  This must be called at

+ 0 - 2
panda/src/collide/config_collide.h

@@ -24,8 +24,6 @@
 
 
 NotifyCategoryDecl(collide, EXPCL_PANDA, EXPTP_PANDA);
 NotifyCategoryDecl(collide, EXPCL_PANDA, EXPTP_PANDA);
 
 
-extern const bool auto_clear_velocity;
-
 extern EXPCL_PANDA void init_libcollide();
 extern EXPCL_PANDA void init_libcollide();
 
 
 #endif
 #endif

+ 2 - 0
panda/src/pgraph/accumulatedAttribs.cxx

@@ -76,6 +76,7 @@ collect(PandaNode *node, int attrib_types) {
     nassertv(_transform != (TransformState *)NULL);
     nassertv(_transform != (TransformState *)NULL);
     _transform = _transform->compose(node->get_transform());
     _transform = _transform->compose(node->get_transform());
     node->set_transform(TransformState::make_identity());
     node->set_transform(TransformState::make_identity());
+    node->reset_prev_transform();
   }
   }
 
 
   if ((attrib_types & SceneGraphReducer::TT_color) != 0) {
   if ((attrib_types & SceneGraphReducer::TT_color) != 0) {
@@ -141,6 +142,7 @@ void AccumulatedAttribs::
 apply_to_node(PandaNode *node, int attrib_types) {
 apply_to_node(PandaNode *node, int attrib_types) {
   if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
   if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
     node->set_transform(_transform->compose(node->get_transform()));
     node->set_transform(_transform->compose(node->get_transform()));
+    node->reset_prev_transform();
     _transform = TransformState::make_identity();
     _transform = TransformState::make_identity();
   }
   }
 
 

+ 59 - 56
panda/src/pgraph/nodePath.I

@@ -417,7 +417,7 @@ get_state() const {
 //  Description: Changes the complete state object on this node.
 //  Description: Changes the complete state object on this node.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void NodePath::
 INLINE void NodePath::
-set_state(const RenderState *state) const {
+set_state(const RenderState *state) {
   nassertv_always(!is_empty());
   nassertv_always(!is_empty());
   node()->set_state(state);
   node()->set_state(state);
 }
 }
@@ -450,7 +450,7 @@ get_transform() const {
 //  Description: Changes the complete transform object on this node.
 //  Description: Changes the complete transform object on this node.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void NodePath::
 INLINE void NodePath::
-set_transform(const TransformState *transform) const {
+set_transform(const TransformState *transform) {
   nassertv_always(!is_empty());
   nassertv_always(!is_empty());
   node()->set_transform(transform);
   node()->set_transform(transform);
 }
 }
@@ -466,17 +466,73 @@ get_net_transform() const {
   return r_get_net_transform(_head);
   return r_get_net_transform(_head);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::get_prev_transform
+//       Access: Published
+//  Description: Returns the transform that has been set as this
+//               node's "previous" position.  See
+//               set_prev_transform().
+////////////////////////////////////////////////////////////////////
+INLINE const TransformState *NodePath::
+get_prev_transform() const {
+  nassertr_always(!is_empty(), TransformState::make_identity());
+  return node()->get_prev_transform();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::set_prev_transform
+//       Access: Published
+//  Description: Sets the transform that represents this node's
+//               "previous" position, one frame ago, for the purposes
+//               of detecting motion for accurate collision
+//               calculations.
+////////////////////////////////////////////////////////////////////
+INLINE void NodePath::
+set_prev_transform(const TransformState *transform) {
+  nassertv_always(!is_empty());
+  node()->set_prev_transform(transform);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::get_net_prev_transform
+//       Access: Published
+//  Description: Returns the net "previous" transform on this node
+//               from the root.  See set_prev_transform().
+////////////////////////////////////////////////////////////////////
+INLINE CPT(TransformState) NodePath::
+get_net_prev_transform() const {
+  uncollapse_head();
+  return r_get_net_prev_transform(_head);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::set_pos
 //     Function: NodePath::set_pos
 //       Access: Published
 //       Access: Published
 //  Description: Sets the translation component of the transform,
 //  Description: Sets the translation component of the transform,
-//               leaving rotation and scale untouched.
+//               leaving rotation and scale untouched.  This also
+//               resets the node's "previous" position, so that the
+//               collision system will see the node as having suddenly
+//               appeared in the new position, without passing any
+//               points in between.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void NodePath::
 INLINE void NodePath::
 set_pos(float x, float y, float z) {
 set_pos(float x, float y, float z) {
   set_pos(LPoint3f(x, y, z));
   set_pos(LPoint3f(x, y, z));
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::set_fluid_pos
+//       Access: Published
+//  Description: Sets the translation component, without changing the
+//               "previous" position, so that the collision system
+//               will see the node as moving fluidly from its previous
+//               position to its new position.
+////////////////////////////////////////////////////////////////////
+INLINE void NodePath::
+set_fluid_pos(float x, float y, float z) {
+  set_fluid_pos(LPoint3f(x, y, z));
+}
+
 INLINE float NodePath::
 INLINE float NodePath::
 get_x() const {
 get_x() const {
   return get_pos()[0];
   return get_pos()[0];
@@ -870,59 +926,6 @@ get_distance(const NodePath &other) const {
   return length(LVector3f(pos));
   return length(LVector3f(pos));
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: NodePath::set_velocity
-//       Access: Published
-//  Description: Sets the velocity of this node.  This is a delta from
-//               the position of this node in the previous frame,
-//               relative to the node's parent.  The value should not
-//               be transformed by the node's transformation (it is in
-//               the coordinate system of the node's parent).  This
-//               has meaning only to the collision subsystem.
-////////////////////////////////////////////////////////////////////
-INLINE void NodePath::
-set_velocity(const LVector3f &velocity) {
-  nassertv_always(!is_empty());
-  node()->set_velocity(velocity);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: NodePath::clear_velocity
-//       Access: Published
-//  Description: Resets the velocity of this node to zero.  See
-//               set_velocity().
-////////////////////////////////////////////////////////////////////
-INLINE void NodePath::
-clear_velocity() {
-  nassertv_always(!is_empty());
-  node()->clear_velocity();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: NodePath::has_velocity
-//       Access: Published
-//  Description: Returns true if a nonzero velocity has been set on
-//               this node, false otherwise.
-////////////////////////////////////////////////////////////////////
-INLINE bool NodePath::
-has_velocity() const {
-  nassertr_always(!is_empty(), false);
-  return node()->has_velocity();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: NodePath::get_velocity
-//       Access: Published
-//  Description: Returns the velocity previously set on this node via
-//               set_velocity(), or LVector3f::zero() if no velocity
-//               has been set.
-////////////////////////////////////////////////////////////////////
-INLINE const LVector3f &NodePath::
-get_velocity() const {
-  nassertr_always(!is_empty(), LVector3f::zero());
-  return node()->get_velocity();
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::set_color_scale
 //     Function: NodePath::set_color_scale
 //       Access: Published
 //       Access: Published

+ 206 - 153
panda/src/pgraph/nodePath.cxx

@@ -291,6 +291,9 @@ reparent_to(const NodePath &other, int sort) {
   uncollapse_head();
   uncollapse_head();
   other.uncollapse_head();
   other.uncollapse_head();
   PandaNode::reparent(other._head, _head, sort);
   PandaNode::reparent(other._head, _head, sort);
+
+  // Reparenting implicitly resents the delta vector.
+  node()->reset_prev_transform();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -309,7 +312,14 @@ wrt_reparent_to(const NodePath &other, int sort) {
   nassertv_always(!is_empty());
   nassertv_always(!is_empty());
   nassertv_always(!other.is_empty());
   nassertv_always(!other.is_empty());
 
 
-  set_transform(get_transform(other));
+  if (get_transform() == get_prev_transform()) {
+    set_transform(get_transform(other));
+    node()->reset_prev_transform();
+  } else {
+    set_transform(get_transform(other));
+    set_prev_transform(get_prev_transform(other));
+  }
+
   reparent_to(other, sort);
   reparent_to(other, sort);
 }
 }
 
 
@@ -343,6 +353,11 @@ instance_to(const NodePath &other, int sort) const {
   NodePath new_instance;
   NodePath new_instance;
   new_instance._head = PandaNode::attach(other._head, node(), sort);
   new_instance._head = PandaNode::attach(other._head, node(), sort);
 
 
+  // instance_to() doesn't reset the velocity delta, unlike most of
+  // the other reparenting operations.  The reasoning is that
+  // instance_to() is not necessarily a reparenting operation, since
+  // it doesn't change the original instance.
+
   return new_instance;
   return new_instance;
 }
 }
 
 
@@ -369,7 +384,7 @@ instance_under_node(const NodePath &other, const string &name, int sort) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::copy_to
 //     Function: NodePath::copy_to
 //       Access: Published
 //       Access: Published
-//  Description: Functions exactly like instance_to(), except a deep
+//  Description: Functions like instance_to(), except a deep
 //               copy is made of the referenced node and all of its
 //               copy is made of the referenced node and all of its
 //               descendents, which is then parented to the indicated
 //               descendents, which is then parented to the indicated
 //               node.  A NodePath to the newly created copy is
 //               node.  A NodePath to the newly created copy is
@@ -386,6 +401,8 @@ copy_to(const NodePath &other, int sort) const {
   PT(PandaNode) copy_node = source_node->copy_subgraph();
   PT(PandaNode) copy_node = source_node->copy_subgraph();
   nassertr(copy_node != (PandaNode *)NULL, fail());
   nassertr(copy_node != (PandaNode *)NULL, fail());
 
 
+  copy_node->reset_prev_transform();
+
   return other.attach_new_node(copy_node, sort);
   return other.attach_new_node(copy_node, sort);
 }
 }
 
 
@@ -444,6 +461,7 @@ remove_node() {
   // In either case, quietly do nothing except to ensure the
   // In either case, quietly do nothing except to ensure the
   // NodePath is clear.
   // NodePath is clear.
   if (!is_empty() && !is_singleton()) {
   if (!is_empty() && !is_singleton()) {
+    node()->reset_prev_transform();
     uncollapse_head();
     uncollapse_head();
     PandaNode::detach(_head);
     PandaNode::detach(_head);
   }
   }
@@ -474,6 +492,7 @@ void NodePath::
 detach_node() {
 detach_node() {
   nassertv(_error_type != ET_not_found);
   nassertv(_error_type != ET_not_found);
   if (!is_empty() && !is_singleton()) {
   if (!is_empty() && !is_singleton()) {
+    node()->reset_prev_transform();
     uncollapse_head();
     uncollapse_head();
     PandaNode::detach(_head);
     PandaNode::detach(_head);
   }
   }
@@ -546,7 +565,7 @@ get_state(const NodePath &other) const {
 //               the other node.
 //               the other node.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void NodePath::
 void NodePath::
-set_state(const NodePath &other, const RenderState *state) const {
+set_state(const NodePath &other, const RenderState *state) {
   nassertv(_error_type == ET_ok && other._error_type == ET_ok);
   nassertv(_error_type == ET_ok && other._error_type == ET_ok);
   nassertv_always(!is_empty());
   nassertv_always(!is_empty());
 
 
@@ -594,7 +613,7 @@ get_transform(const NodePath &other) const {
 //               other node.
 //               other node.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void NodePath::
 void NodePath::
-set_transform(const NodePath &other, const TransformState *transform) const {
+set_transform(const NodePath &other, const TransformState *transform) {
   nassertv(_error_type == ET_ok && other._error_type == ET_ok);
   nassertv(_error_type == ET_ok && other._error_type == ET_ok);
   nassertv_always(!is_empty());
   nassertv_always(!is_empty());
 
 
@@ -610,16 +629,74 @@ set_transform(const NodePath &other, const TransformState *transform) const {
   set_transform(new_trans);
   set_transform(new_trans);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::get_prev_transform
+//       Access: Published
+//  Description: Returns the relative "previous" transform to this
+//               node from the other node; i.e. the position of this
+//               node in the previous frame, as seen by the other node
+//               in the previous frame.
+////////////////////////////////////////////////////////////////////
+CPT(TransformState) NodePath::
+get_prev_transform(const NodePath &other) const {
+  if (other.is_empty()) {
+    return get_net_prev_transform();
+  }
+  if (is_empty()) {
+    return other.get_net_prev_transform()->invert_compose(TransformState::make_identity());
+  }
+    
+  nassertr(verify_complete(), TransformState::make_identity());
+  nassertr(other.verify_complete(), TransformState::make_identity());
+
+  int a_count, b_count;
+  find_common_ancestor(*this, other, a_count, b_count);
+
+  CPT(TransformState) a_prev_transform = r_get_partial_prev_transform(_head, a_count);
+  CPT(TransformState) b_prev_transform = r_get_partial_prev_transform(other._head, b_count);
+  return b_prev_transform->invert_compose(a_prev_transform);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::set_prev_transform
+//       Access: Published
+//  Description: Sets the "previous" transform object on this node,
+//               relative to the other node.  This computes a new
+//               transform object that will have the indicated value
+//               when seen from the other node.
+////////////////////////////////////////////////////////////////////
+void NodePath::
+set_prev_transform(const NodePath &other, const TransformState *transform) {
+  nassertv(_error_type == ET_ok && other._error_type == ET_ok);
+  nassertv_always(!is_empty());
+
+  // First, we perform a wrt to the parent, to get the conversion.
+  CPT(TransformState) rel_trans;
+  if (has_parent()) {
+    rel_trans = other.get_prev_transform(get_parent());
+  } else {
+    rel_trans = other.get_prev_transform(NodePath());
+  }
+
+  CPT(TransformState) new_trans = rel_trans->compose(transform);
+  set_prev_transform(new_trans);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::set_pos
 //     Function: NodePath::set_pos
 //       Access: Published
 //       Access: Published
 //  Description: Sets the translation component of the transform,
 //  Description: Sets the translation component of the transform,
-//               leaving rotation and scale untouched.
+//               leaving rotation and scale untouched.  This also
+//               resets the node's "previous" position, so that the
+//               collision system will see the node as having suddenly
+//               appeared in the new position, without passing any
+//               points in between.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void NodePath::
 void NodePath::
 set_pos(const LVecBase3f &pos) {
 set_pos(const LVecBase3f &pos) {
   nassertv_always(!is_empty());
   nassertv_always(!is_empty());
   set_transform(get_transform()->set_pos(pos));
   set_transform(get_transform()->set_pos(pos));
+  node()->reset_prev_transform();
 }
 }
 
 
 void NodePath::
 void NodePath::
@@ -646,6 +723,44 @@ set_z(float z) {
   set_pos(pos);
   set_pos(pos);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::set_fluid_pos
+//       Access: Published
+//  Description: Sets the translation component, without changing the
+//               "previous" position, so that the collision system
+//               will see the node as moving fluidly from its previous
+//               position to its new position.
+////////////////////////////////////////////////////////////////////
+void NodePath::
+set_fluid_pos(const LVecBase3f &pos) {
+  nassertv_always(!is_empty());
+  set_transform(get_transform()->set_pos(pos));
+}
+
+void NodePath::
+set_fluid_x(float x) {
+  nassertv_always(!is_empty());
+  LPoint3f pos = get_pos();
+  pos[0] = x;
+  set_fluid_pos(pos);
+}
+
+void NodePath::
+set_fluid_y(float y) {
+  nassertv_always(!is_empty());
+  LPoint3f pos = get_pos();
+  pos[1] = y;
+  set_fluid_pos(pos);
+}
+
+void NodePath::
+set_fluid_z(float z) {
+  nassertv_always(!is_empty());
+  LPoint3f pos = get_pos();
+  pos[2] = z;
+  set_fluid_pos(pos);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::get_pos
 //     Function: NodePath::get_pos
 //       Access: Published
 //       Access: Published
@@ -657,6 +772,26 @@ get_pos() const {
   return get_transform()->get_pos();
   return get_transform()->get_pos();
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::get_pos_delta
+//       Access: Published
+//  Description: Returns the delta vector from this node's position in
+//               the previous frame (according to
+//               set_prev_transform(), typically set via the use of
+//               set_fluid_pos()) and its position in the current
+//               frame.  This is the vector used to determine
+//               collisions.  Generally, if the node was last
+//               repositioned via set_pos(), the delta will be zero;
+//               if it was adjusted via set_fluid_pos(), the delta
+//               will represent the change from the previous frame's
+//               position.
+////////////////////////////////////////////////////////////////////
+LVector3f NodePath::
+get_pos_delta() const {
+  nassertr_always(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f));
+  return get_transform()->get_pos() - get_prev_transform()->get_pos();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::set_hpr
 //     Function: NodePath::set_hpr
 //       Access: Published
 //       Access: Published
@@ -856,6 +991,7 @@ set_pos_hpr(const LVecBase3f &pos, const LVecBase3f &hpr) {
   transform = TransformState::make_pos_hpr_scale_shear
   transform = TransformState::make_pos_hpr_scale_shear
     (pos, hpr, transform->get_scale(), transform->get_shear());
     (pos, hpr, transform->get_scale(), transform->get_shear());
   set_transform(transform);
   set_transform(transform);
+  node()->reset_prev_transform();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -885,6 +1021,7 @@ set_pos_hpr_scale(const LVecBase3f &pos, const LVecBase3f &hpr,
   nassertv_always(!is_empty());
   nassertv_always(!is_empty());
   set_transform(TransformState::make_pos_hpr_scale
   set_transform(TransformState::make_pos_hpr_scale
                 (pos, hpr, scale));
                 (pos, hpr, scale));
+  node()->reset_prev_transform();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -899,6 +1036,7 @@ set_pos_quat_scale(const LVecBase3f &pos, const LQuaternionf &quat,
   nassertv_always(!is_empty());
   nassertv_always(!is_empty());
   set_transform(TransformState::make_pos_quat_scale
   set_transform(TransformState::make_pos_quat_scale
                 (pos, quat, scale));
                 (pos, quat, scale));
+  node()->reset_prev_transform();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -913,6 +1051,7 @@ set_pos_hpr_scale_shear(const LVecBase3f &pos, const LVecBase3f &hpr,
   nassertv_always(!is_empty());
   nassertv_always(!is_empty());
   set_transform(TransformState::make_pos_hpr_scale_shear
   set_transform(TransformState::make_pos_hpr_scale_shear
                 (pos, hpr, scale, shear));
                 (pos, hpr, scale, shear));
+  node()->reset_prev_transform();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -927,6 +1066,7 @@ set_pos_quat_scale_shear(const LVecBase3f &pos, const LQuaternionf &quat,
   nassertv_always(!is_empty());
   nassertv_always(!is_empty());
   set_transform(TransformState::make_pos_quat_scale_shear
   set_transform(TransformState::make_pos_quat_scale_shear
                 (pos, quat, scale, shear));
                 (pos, quat, scale, shear));
+  node()->reset_prev_transform();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -938,6 +1078,7 @@ void NodePath::
 set_mat(const LMatrix4f &mat) {
 set_mat(const LMatrix4f &mat) {
   nassertv_always(!is_empty());
   nassertv_always(!is_empty());
   set_transform(TransformState::make_mat(mat));
   set_transform(TransformState::make_mat(mat));
+  node()->reset_prev_transform();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -1003,6 +1144,7 @@ set_pos(const NodePath &other, const LVecBase3f &pos) {
     // If we didn't have a componentwise transform already, never
     // If we didn't have a componentwise transform already, never
     // mind.
     // mind.
     set_transform(other, rel_transform->set_pos(pos));
     set_transform(other, rel_transform->set_pos(pos));
+    node()->reset_prev_transform();
   }
   }
 }
 }
 
 
@@ -1042,6 +1184,27 @@ get_pos(const NodePath &other) const {
   return get_transform(other)->get_pos();
   return get_transform(other)->get_pos();
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::get_pos_delta
+//       Access: Published
+//  Description: Returns the delta vector from this node's position in
+//               the previous frame (according to
+//               set_prev_transform(), typically set via the use of
+//               set_fluid_pos()) and its position in the current
+//               frame, as seen in the indicated node's coordinate
+//               space.  This is the vector used to determine
+//               collisions.  Generally, if the node was last
+//               repositioned via set_pos(), the delta will be zero;
+//               if it was adjusted via set_fluid_pos(), the delta
+//               will represent the change from the previous frame's
+//               position.
+////////////////////////////////////////////////////////////////////
+LVector3f NodePath::
+get_pos_delta(const NodePath &other) const {
+  nassertr_always(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f));
+  return get_transform(other)->get_pos() - get_prev_transform(other)->get_pos();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::set_hpr
 //     Function: NodePath::set_hpr
 //       Access: Published
 //       Access: Published
@@ -1067,7 +1230,8 @@ set_hpr(const NodePath &other, const LVecBase3f &hpr) {
     set_transform(other, rel_transform->set_hpr(hpr));
     set_transform(other, rel_transform->set_hpr(hpr));
     const TransformState *new_transform = get_transform();
     const TransformState *new_transform = get_transform();
     if (new_transform->has_components()) {
     if (new_transform->has_components()) {
-      set_pos_hpr_scale_shear(orig_pos, new_transform->get_hpr(), orig_scale, orig_shear);
+      set_transform(TransformState::make_pos_hpr_scale_shear
+                    (orig_pos, new_transform->get_hpr(), orig_scale, orig_shear));
     }
     }
 
 
   } else {
   } else {
@@ -1139,7 +1303,8 @@ set_quat(const NodePath &other, const LQuaternionf &quat) {
     set_transform(other, rel_transform->set_quat(quat));
     set_transform(other, rel_transform->set_quat(quat));
     const TransformState *new_transform = get_transform();
     const TransformState *new_transform = get_transform();
     if (new_transform->has_components()) {
     if (new_transform->has_components()) {
-      set_pos_quat_scale_shear(orig_pos, new_transform->get_quat(), orig_scale, orig_shear);
+      set_transform(TransformState::make_pos_quat_scale_shear
+                    (orig_pos, new_transform->get_quat(), orig_scale, orig_shear));
     }
     }
 
 
   } else {
   } else {
@@ -1186,7 +1351,8 @@ set_scale(const NodePath &other, const LVecBase3f &scale) {
     set_transform(other, rel_transform->set_scale(scale));
     set_transform(other, rel_transform->set_scale(scale));
     const TransformState *new_transform = get_transform();
     const TransformState *new_transform = get_transform();
     if (new_transform->has_components()) {
     if (new_transform->has_components()) {
-      set_pos_hpr_scale_shear(orig_pos, orig_hpr, new_transform->get_scale(), orig_shear);
+      set_transform(TransformState::make_pos_hpr_scale_shear
+                    (orig_pos, orig_hpr, new_transform->get_scale(), orig_shear));
     }
     }
 
 
   } else {
   } else {
@@ -1257,7 +1423,8 @@ set_shear(const NodePath &other, const LVecBase3f &shear) {
     set_transform(other, rel_transform->set_shear(shear));
     set_transform(other, rel_transform->set_shear(shear));
     const TransformState *new_transform = get_transform();
     const TransformState *new_transform = get_transform();
     if (new_transform->has_components()) {
     if (new_transform->has_components()) {
-      set_pos_hpr_scale_shear(orig_pos, orig_hpr, orig_scale, new_transform->get_shear());
+      set_transform(TransformState::make_pos_hpr_scale_shear
+                    (orig_pos, orig_hpr, orig_scale, new_transform->get_shear()));
     }
     }
 
 
   } else {
   } else {
@@ -1338,6 +1505,7 @@ set_pos_hpr(const NodePath &other, const LVecBase3f &pos,
     // mind.
     // mind.
     set_transform(other, TransformState::make_pos_hpr_scale_shear
     set_transform(other, TransformState::make_pos_hpr_scale_shear
                   (pos, hpr, rel_transform->get_scale(), rel_transform->get_shear()));
                   (pos, hpr, rel_transform->get_scale(), rel_transform->get_shear()));
+    node()->reset_prev_transform();
   }
   }
 }
 }
 
 
@@ -1376,6 +1544,7 @@ set_pos_hpr_scale(const NodePath &other,
   nassertv_always(!is_empty());
   nassertv_always(!is_empty());
   set_transform(other, TransformState::make_pos_hpr_scale
   set_transform(other, TransformState::make_pos_hpr_scale
                 (pos, hpr, scale));
                 (pos, hpr, scale));
+  node()->reset_prev_transform();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -1392,6 +1561,7 @@ set_pos_quat_scale(const NodePath &other,
   nassertv_always(!is_empty());
   nassertv_always(!is_empty());
   set_transform(other, TransformState::make_pos_quat_scale
   set_transform(other, TransformState::make_pos_quat_scale
                 (pos, quat, scale));
                 (pos, quat, scale));
+  node()->reset_prev_transform();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -1408,6 +1578,7 @@ set_pos_hpr_scale_shear(const NodePath &other,
   nassertv_always(!is_empty());
   nassertv_always(!is_empty());
   set_transform(other, TransformState::make_pos_hpr_scale_shear
   set_transform(other, TransformState::make_pos_hpr_scale_shear
                 (pos, hpr, scale, shear));
                 (pos, hpr, scale, shear));
+  node()->reset_prev_transform();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -1424,6 +1595,7 @@ set_pos_quat_scale_shear(const NodePath &other,
   nassertv_always(!is_empty());
   nassertv_always(!is_empty());
   set_transform(other, TransformState::make_pos_quat_scale_shear
   set_transform(other, TransformState::make_pos_quat_scale_shear
                 (pos, quat, scale, shear));
                 (pos, quat, scale, shear));
+  node()->reset_prev_transform();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -1455,6 +1627,7 @@ void NodePath::
 set_mat(const NodePath &other, const LMatrix4f &mat) {
 set_mat(const NodePath &other, const LMatrix4f &mat) {
   nassertv_always(!is_empty());
   nassertv_always(!is_empty());
   set_transform(other, TransformState::make_mat(mat));
   set_transform(other, TransformState::make_mat(mat));
+  node()->reset_prev_transform();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -1525,106 +1698,6 @@ heads_up(const NodePath &other, const LPoint3f &point, const LVector3f &up) {
   set_quat(quat);
   set_quat(quat);
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: NodePath::get_velocity
-//       Access: Published
-//  Description: Returns the relative velocity to this node from the
-//               other node; i.e. the velocity of this node as seen
-//               from the other node.
-////////////////////////////////////////////////////////////////////
-LVector3f NodePath::
-get_velocity(const NodePath &other) const {
-  if (other.is_empty()) {
-    return get_net_velocity();
-  }
-  if (is_empty()) {
-    other.uncollapse_head();
-    CPT(TransformState) net_transform = TransformState::make_identity();
-    CPT(TransformState) parent_transform = net_transform;
-    LVector3f net_velocity = LVector3f::zero();
-    r_get_net_velocity(other._head, net_velocity, net_transform, parent_transform);
-    return -net_velocity;
-  }
-    
-  nassertr(verify_complete(), LVector3f::zero());
-  nassertr(other.verify_complete(), LVector3f::zero());
-
-  int a_count, b_count;
-  find_common_ancestor(*this, other, a_count, b_count);
-
-  // Now compute the net velocity of each node, by working down from
-  // the common ancestor.
-  CPT(TransformState) a_transform = TransformState::make_identity();
-  CPT(TransformState) a_parent_transform = a_transform;
-  LVector3f a_velocity = LVector3f::zero();
-  r_get_partial_velocity(_head, a_count, a_velocity, a_transform, 
-                         a_parent_transform);
-
-  CPT(TransformState) b_transform = TransformState::make_identity();
-  CPT(TransformState) b_parent_transform = b_transform;
-  LVector3f b_velocity = LVector3f::zero();
-  r_get_partial_velocity(other._head, b_count, b_velocity, b_transform, 
-                         b_parent_transform);
-
-  LVector3f net_velocity = a_velocity - b_velocity;
-  
-  // Finally, convert the net velocity back into the parent's
-  // coordinate space.
-  CPT(TransformState) a_parent_inverse = 
-    a_parent_transform->invert_compose(TransformState::make_identity());
-  return net_velocity * a_parent_inverse->get_mat();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: NodePath::set_velocity
-//       Access: Published
-//  Description: Sets the velocity of this node, relative to the other
-//               node.  This computes a new velocity that will have
-//               the indicated value when seen from the other node.
-////////////////////////////////////////////////////////////////////
-void NodePath::
-set_velocity(const NodePath &other, const LVector3f &velocity) {
-  nassertv(_error_type == ET_ok && other._error_type == ET_ok);
-  nassertv_always(!is_empty());
-
-  // First, we perform a wrt to the parent, to get the conversion.
-  LVector3f rel_velocity;
-  if (has_parent()) {
-    rel_velocity = other.get_velocity(get_parent());
-  } else {
-    rel_velocity = other.get_velocity(NodePath());
-  }
-
-  LVector3f new_velocity = velocity + rel_velocity;
-  set_velocity(new_velocity);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: NodePath::get_net_velocity
-//       Access: Published
-//  Description: Returns the relative "velocity" of this node (as
-//               reported by get_velocity()) from the root of the
-//               scene graph, accumulating all velocity values set on
-//               ancestor nodes.  The result is returned in the
-//               coordinate space of the node's parent (the same
-//               coordinate space in which get_velocity() is
-//               returned).
-////////////////////////////////////////////////////////////////////
-LVector3f NodePath::
-get_net_velocity() const {
-  uncollapse_head();
-  CPT(TransformState) net_transform = TransformState::make_identity();
-  CPT(TransformState) parent_transform = net_transform;
-  LVector3f net_velocity = LVector3f::zero();
-  r_get_net_velocity(_head, net_velocity, net_transform, parent_transform);
-
-  // Convert the net velocity back from global coordinates into the
-  // parent's coordinate space.
-  CPT(TransformState) parent_inverse = 
-    parent_transform->invert_compose(TransformState::make_identity());
-  return net_velocity * parent_inverse->get_mat();
-}
-
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::set_color
 //     Function: NodePath::set_color
@@ -3442,58 +3515,38 @@ r_get_partial_transform(NodePathComponent *comp, int n) const {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: NodePath::r_get_net_velocity
+//     Function: NodePath::r_get_net_prev_transform
 //       Access: Private
 //       Access: Private
-//  Description: Recursively determines the net velocity of the
-//               indicated node; the result is returned in the global
-//               coordinate space.
+//  Description: Recursively determines the net "previous" transform
+//               to the indicated component node from the root of the
+//               graph.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void NodePath::
-r_get_net_velocity(NodePathComponent *comp, LVector3f &net_vel, 
-                   CPT(TransformState) &net_transform,
-                   CPT(TransformState) &parent_net_transform) const {
-  if (comp != (NodePathComponent *)NULL) {
-    r_get_net_velocity(comp->get_next(), net_vel, net_transform, 
-                       parent_net_transform);
-
-    PandaNode *node = comp->get_node();
-    if (node->has_velocity()) {
-      LVector3f vel = node->get_velocity();
-      net_vel += vel * net_transform->get_mat();
-    }
-    
-    CPT(TransformState) transform = node->get_transform();
-    parent_net_transform = net_transform;
-    net_transform = net_transform->compose(transform);
+CPT(TransformState) NodePath::
+r_get_net_prev_transform(NodePathComponent *comp) const {
+  if (comp == (NodePathComponent *)NULL) {
+    return TransformState::make_identity();
+  } else {
+    CPT(TransformState) transform = comp->get_node()->get_prev_transform();
+    return r_get_net_prev_transform(comp->get_next())->compose(transform);
   }
   }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: NodePath::r_get_partial_velocity
+//     Function: NodePath::r_get_partial_prev_transform
 //       Access: Private
 //       Access: Private
-//  Description: Recursively determines the net velocity of the
-//               indicated component node from the nth node above it.
-//               If n exceeds the length of the path, this returns the
-//               net velocity from the root of the graph.
+//  Description: Recursively determines the net "previous" transform
+//               to the indicated component node from the nth node
+//               above it.  If n exceeds the length of the path, this
+//               returns the net previous transform from the root of
+//               the graph.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void NodePath::
-r_get_partial_velocity(NodePathComponent *comp, int n, 
-                       LVector3f &net_vel,
-                       CPT(TransformState) &net_transform,
-                       CPT(TransformState) &parent_net_transform) const {
-  if (n != 0 && comp != (NodePathComponent *)NULL) {
-    r_get_partial_velocity(comp->get_next(), n - 1, net_vel, net_transform,
-                           parent_net_transform);
-    
-    PandaNode *node = comp->get_node();
-    if (node->has_velocity()) {
-      LVector3f vel = node->get_velocity();
-      net_vel += vel * net_transform->get_mat();
-    }
-    
-    CPT(TransformState) transform = node->get_transform();
-    parent_net_transform = net_transform;
-    net_transform = net_transform->compose(transform);
+CPT(TransformState) NodePath::
+r_get_partial_prev_transform(NodePathComponent *comp, int n) const {
+  if (n == 0 || comp == (NodePathComponent *)NULL) {
+    return TransformState::make_identity();
+  } else {
+    CPT(TransformState) transform = comp->get_node()->get_prev_transform();
+    return r_get_partial_prev_transform(comp->get_next(), n - 1)->compose(transform);
   }
   }
 }
 }
 
 

+ 21 - 23
panda/src/pgraph/nodePath.h

@@ -225,17 +225,23 @@ PUBLISHED:
 
 
   // Aggregate transform and state information.
   // Aggregate transform and state information.
   INLINE const RenderState *get_state() const;
   INLINE const RenderState *get_state() const;
-  INLINE void set_state(const RenderState *state) const;
+  INLINE void set_state(const RenderState *state);
   CPT(RenderState) get_state(const NodePath &other) const;
   CPT(RenderState) get_state(const NodePath &other) const;
-  void set_state(const NodePath &other, const RenderState *state) const;
+  void set_state(const NodePath &other, const RenderState *state);
   INLINE CPT(RenderState) get_net_state() const;
   INLINE CPT(RenderState) get_net_state() const;
 
 
   INLINE const TransformState *get_transform() const;
   INLINE const TransformState *get_transform() const;
-  INLINE void set_transform(const TransformState *transform) const;
+  INLINE void set_transform(const TransformState *transform);
   CPT(TransformState) get_transform(const NodePath &other) const;
   CPT(TransformState) get_transform(const NodePath &other) const;
-  void set_transform(const NodePath &other, const TransformState *transform) const;
+  void set_transform(const NodePath &other, const TransformState *transform);
   INLINE CPT(TransformState) get_net_transform() const;
   INLINE CPT(TransformState) get_net_transform() const;
 
 
+  INLINE const TransformState *get_prev_transform() const;
+  INLINE void set_prev_transform(const TransformState *transform);
+  CPT(TransformState) get_prev_transform(const NodePath &other) const;
+  void set_prev_transform(const NodePath &other, const TransformState *transform);
+  INLINE CPT(TransformState) get_net_prev_transform() const;
+
 
 
   // Methods that get and set the matrix transform: pos, hpr, scale,
   // Methods that get and set the matrix transform: pos, hpr, scale,
   // in the local coordinate system.
   // in the local coordinate system.
@@ -245,11 +251,18 @@ PUBLISHED:
   void set_x(float x);
   void set_x(float x);
   void set_y(float y);
   void set_y(float y);
   void set_z(float z);
   void set_z(float z);
+  INLINE void set_fluid_pos(float x, float y, float z);
+  void set_fluid_pos(const LVecBase3f &pos);
+  void set_fluid_x(float x);
+  void set_fluid_y(float y);
+  void set_fluid_z(float z);
   LPoint3f get_pos() const;
   LPoint3f get_pos() const;
   INLINE float get_x() const;
   INLINE float get_x() const;
   INLINE float get_y() const;
   INLINE float get_y() const;
   INLINE float get_z() const;
   INLINE float get_z() const;
 
 
+  LVector3f get_pos_delta() const;
+
   INLINE void set_hpr(float h, float p, float r);
   INLINE void set_hpr(float h, float p, float r);
   void set_hpr(const LVecBase3f &hpr);
   void set_hpr(const LVecBase3f &hpr);
   void set_h(float h);
   void set_h(float h);
@@ -334,6 +347,8 @@ PUBLISHED:
   INLINE float get_y(const NodePath &other) const;
   INLINE float get_y(const NodePath &other) const;
   INLINE float get_z(const NodePath &other) const;
   INLINE float get_z(const NodePath &other) const;
 
 
+  LVector3f get_pos_delta(const NodePath &other) const;
+
   INLINE void set_hpr(const NodePath &other, float h, float p, float r);
   INLINE void set_hpr(const NodePath &other, float h, float p, float r);
   void set_hpr(const NodePath &other, const LVecBase3f &hpr);
   void set_hpr(const NodePath &other, const LVecBase3f &hpr);
   void set_h(const NodePath &other, float h);
   void set_h(const NodePath &other, float h);
@@ -421,17 +436,6 @@ PUBLISHED:
 
 
   INLINE float get_distance(const NodePath &other) const;
   INLINE float get_distance(const NodePath &other) const;
 
 
-  INLINE void set_velocity(const LVector3f &velocity);
-  INLINE void clear_velocity();
-  INLINE bool has_velocity() const;
-  INLINE const LVector3f &get_velocity() const;
-
-  LVector3f get_velocity(const NodePath &other) const;
-  void set_velocity(const NodePath &other, const LVector3f &velocity);
-
-  LVector3f get_net_velocity() const;
-  
-
   // Methods that affect appearance of geometry: color, texture, etc.
   // Methods that affect appearance of geometry: color, texture, etc.
   // These affect the state at the bottom level only.
   // These affect the state at the bottom level only.
 
 
@@ -595,14 +599,8 @@ private:
   CPT(RenderState) r_get_partial_state(NodePathComponent *comp, int n) const;
   CPT(RenderState) r_get_partial_state(NodePathComponent *comp, int n) const;
   CPT(TransformState) r_get_net_transform(NodePathComponent *comp) const;
   CPT(TransformState) r_get_net_transform(NodePathComponent *comp) const;
   CPT(TransformState) r_get_partial_transform(NodePathComponent *comp, int n) const;
   CPT(TransformState) r_get_partial_transform(NodePathComponent *comp, int n) const;
-
-  void r_get_net_velocity(NodePathComponent *comp, LVector3f &net_vel, 
-                          CPT(TransformState) &net_transform,
-                          CPT(TransformState) &parent_net_transform) const;
-  void r_get_partial_velocity(NodePathComponent *comp, int n, 
-                              LVector3f &net_vel, 
-                              CPT(TransformState) &net_transform,
-                              CPT(TransformState) &parent_net_transform) const;
+  CPT(TransformState) r_get_net_prev_transform(NodePathComponent *comp) const;
+  CPT(TransformState) r_get_partial_prev_transform(NodePathComponent *comp, int n) const;
 
 
   void find_matches(NodePathCollection &result,
   void find_matches(NodePathCollection &result,
                     const string &approx_path_str,
                     const string &approx_path_str,

+ 42 - 59
panda/src/pgraph/pandaNode.I

@@ -118,9 +118,8 @@ CData() {
   _state = RenderState::make_empty();
   _state = RenderState::make_empty();
   _effects = RenderEffects::make_empty();
   _effects = RenderEffects::make_empty();
   _transform = TransformState::make_identity();
   _transform = TransformState::make_identity();
+  _prev_transform = TransformState::make_identity();
   _draw_mask = DrawMask::all_on();
   _draw_mask = DrawMask::all_on();
-  _velocity = LVector3f::zero();
-  _has_velocity = false;
   _net_collide_mask = CollideMask::all_off();
   _net_collide_mask = CollideMask::all_off();
   _fixed_internal_bound = false;
   _fixed_internal_bound = false;
 }
 }
@@ -139,10 +138,9 @@ CData(const PandaNode::CData &copy) :
   _state(copy._state),
   _state(copy._state),
   _effects(copy._effects),
   _effects(copy._effects),
   _transform(copy._transform),
   _transform(copy._transform),
+  _prev_transform(copy._prev_transform),
   _tag_data(copy._tag_data),
   _tag_data(copy._tag_data),
   _draw_mask(copy._draw_mask),
   _draw_mask(copy._draw_mask),
-  _velocity(copy._velocity),
-  _has_velocity(copy._has_velocity),
   _fixed_internal_bound(copy._fixed_internal_bound)
   _fixed_internal_bound(copy._fixed_internal_bound)
 {
 {
   _net_collide_mask = CollideMask::all_off();
   _net_collide_mask = CollideMask::all_off();
@@ -662,6 +660,46 @@ clear_transform() {
   transform_changed();
   transform_changed();
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::set_prev_transform
+//       Access: Published
+//  Description: Sets the transform that represents this node's
+//               "previous" position, one frame ago, for the purposes
+//               of detecting motion for accurate collision
+//               calculations.
+////////////////////////////////////////////////////////////////////
+INLINE void PandaNode::
+set_prev_transform(const TransformState *transform) {
+  CDWriter cdata(_cycler);
+  cdata->_prev_transform = transform;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::get_prev_transform
+//       Access: Published
+//  Description: Returns the transform that has been set as this
+//               node's "previous" position.  See
+//               set_prev_transform().
+////////////////////////////////////////////////////////////////////
+INLINE const TransformState *PandaNode::
+get_prev_transform() const {
+  CDReader cdata(_cycler);
+  return cdata->_prev_transform;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::reset_prev_transform
+//       Access: Published
+//  Description: Resets the "previous" transform on this node to be
+//               the same as the current transform.  This is not the
+//               same as clearing it to identity.
+////////////////////////////////////////////////////////////////////
+INLINE void PandaNode::
+reset_prev_transform() {
+  CDWriter cdata(_cycler);
+  cdata->_prev_transform = cdata->_transform;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PandaNode::set_tag
 //     Function: PandaNode::set_tag
 //       Access: Published
 //       Access: Published
@@ -784,61 +822,6 @@ get_net_collide_mask() const {
   return cdata->_net_collide_mask;
   return cdata->_net_collide_mask;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: PandaNode::set_velocity
-//       Access: Published
-//  Description: Sets the velocity of this node.  This is a delta from
-//               the position of this node in the previous frame,
-//               relative to the node's parent.  The value should not
-//               be transformed by the node's transformation (it is in
-//               the coordinate system of the node's parent).  This
-//               has meaning only to the collision subsystem.
-////////////////////////////////////////////////////////////////////
-INLINE void PandaNode::
-set_velocity(const LVector3f &velocity) {
-  CDWriter cdata(_cycler);
-  cdata->_velocity = velocity;
-  cdata->_has_velocity = (!velocity.almost_equal(LVector3f::zero()));
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PandaNode::clear_velocity
-//       Access: Published
-//  Description: Resets the velocity of this node to zero.  See
-//               set_velocity().
-////////////////////////////////////////////////////////////////////
-INLINE void PandaNode::
-clear_velocity() {
-  CDWriter cdata(_cycler);
-  cdata->_velocity = LVector3f::zero();
-  cdata->_has_velocity = false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PandaNode::has_velocity
-//       Access: Published
-//  Description: Returns true if a nonzero velocity has been set on
-//               this node, false otherwise.
-////////////////////////////////////////////////////////////////////
-INLINE bool PandaNode::
-has_velocity() const {
-  CDReader cdata(_cycler);
-  return cdata->_has_velocity;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PandaNode::get_velocity
-//       Access: Published
-//  Description: Returns the velocity previously set on this node via
-//               set_velocity(), or LVector3f::zero() if no velocity
-//               has been set.
-////////////////////////////////////////////////////////////////////
-INLINE const LVector3f &PandaNode::
-get_velocity() const {
-  CDReader cdata(_cycler);
-  return cdata->_velocity;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PandaNode::set_bound
 //     Function: PandaNode::set_bound
 //       Access: Published
 //       Access: Published

+ 5 - 8
panda/src/pgraph/pandaNode.h

@@ -150,6 +150,10 @@ PUBLISHED:
   INLINE const TransformState *get_transform() const;
   INLINE const TransformState *get_transform() const;
   INLINE void clear_transform();
   INLINE void clear_transform();
 
 
+  INLINE void set_prev_transform(const TransformState *transform);
+  INLINE const TransformState *get_prev_transform() const;
+  INLINE void reset_prev_transform();
+
   INLINE void set_tag(const string &key, const string &value);
   INLINE void set_tag(const string &key, const string &value);
   INLINE string get_tag(const string &key) const;
   INLINE string get_tag(const string &key) const;
   INLINE bool has_tag(const string &key) const;
   INLINE bool has_tag(const string &key) const;
@@ -162,11 +166,6 @@ PUBLISHED:
 
 
   INLINE CollideMask get_net_collide_mask() const;
   INLINE CollideMask get_net_collide_mask() const;
 
 
-  INLINE void set_velocity(const LVector3f &velocity);
-  INLINE void clear_velocity();
-  INLINE bool has_velocity() const;
-  INLINE const LVector3f &get_velocity() const;
-
   virtual void output(ostream &out) const;
   virtual void output(ostream &out) const;
   virtual void write(ostream &out, int indent_level) const;
   virtual void write(ostream &out, int indent_level) const;
 
 
@@ -314,15 +313,13 @@ private:
     CPT(RenderState) _state;
     CPT(RenderState) _state;
     CPT(RenderEffects) _effects;
     CPT(RenderEffects) _effects;
     CPT(TransformState) _transform;
     CPT(TransformState) _transform;
+    CPT(TransformState) _prev_transform;
 
 
     TagData _tag_data;
     TagData _tag_data;
 
 
     // This is the draw_mask of this particular node.
     // This is the draw_mask of this particular node.
     DrawMask _draw_mask;
     DrawMask _draw_mask;
 
 
-    LVector3f _velocity;
-    bool _has_velocity;
-
     // This is the union of all into_collide_mask bits for any
     // This is the union of all into_collide_mask bits for any
     // CollisionNodes at and below this level.  It's conceptually
     // CollisionNodes at and below this level.  It's conceptually
     // similar to a bounding volume--it represents the bounding volume
     // similar to a bounding volume--it represents the bounding volume

+ 0 - 38
panda/src/tform/transform2sg.cxx

@@ -32,10 +32,8 @@ Transform2SG(const string &name) :
   DataNode(name)
   DataNode(name)
 {
 {
   _transform_input = define_input("transform", EventStoreTransform::get_class_type());
   _transform_input = define_input("transform", EventStoreTransform::get_class_type());
-  _velocity_input = define_input("velocity", EventStoreVec3::get_class_type());
 
 
   _node = NULL;
   _node = NULL;
-  _velocity_node = NULL;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -59,33 +57,6 @@ get_node() const {
   return _node;
   return _node;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: Transform2SG::set_velocity_node
-//       Access: Public
-//  Description: Sets the node that this object will assign the
-//               computed velocity to.  Normally this is a
-//               CollisionNode parented below the node indicated by
-//               set_node().  Setting this node allows the collision
-//               system to track the velocity imparted to the
-//               CollisionNode by the data graph object that set its
-//               transform, if that data is available.
-////////////////////////////////////////////////////////////////////
-void Transform2SG::
-set_velocity_node(PandaNode *node) {
-  _velocity_node = node;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Transform2SG::get_velocity_node
-//       Access: Public
-//  Description: Returns the node that this object will assign the
-//               computed velocity to.  See set_velocity_node().
-////////////////////////////////////////////////////////////////////
-PandaNode *Transform2SG::
-get_velocity_node() const {
-  return _velocity_node;
-}
-
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Transform2SG::do_transmit_data
 //     Function: Transform2SG::do_transmit_data
@@ -110,13 +81,4 @@ do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &) {
       _node->set_transform(ts);
       _node->set_transform(ts);
     }
     }
   }
   }
-
-  if (input.has_data(_velocity_input)) {
-    const EventStoreVec3 *velocity;
-    DCAST_INTO_V(velocity, input.get_data(_velocity_input).get_ptr());
-    LVector3f vel = velocity->get_value();
-    if (_velocity_node != (PandaNode *)NULL) {
-      _velocity_node->set_velocity(vel);
-    }
-  }
 }
 }

+ 0 - 5
panda/src/tform/transform2sg.h

@@ -38,12 +38,8 @@ PUBLISHED:
   void set_node(PandaNode *node);
   void set_node(PandaNode *node);
   PandaNode *get_node() const;
   PandaNode *get_node() const;
 
 
-  void set_velocity_node(PandaNode *node);
-  PandaNode *get_velocity_node() const;
-
 private:
 private:
   PandaNode *_node;
   PandaNode *_node;
-  PandaNode *_velocity_node;
 
 
 protected:
 protected:
   // Inherited from DataNode
   // Inherited from DataNode
@@ -53,7 +49,6 @@ protected:
 private:
 private:
   // inputs
   // inputs
   int _transform_input;
   int _transform_input;
-  int _velocity_input;
 
 
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {