Browse Source

factor out Thread::get_current_thread() some more

David Rose 19 years ago
parent
commit
ddd1046462
100 changed files with 1199 additions and 986 deletions
  1. 2 1
      panda/src/char/character.cxx
  2. 2 1
      panda/src/char/character.h
  3. 2 2
      panda/src/collide/collisionNode.cxx
  4. 1 1
      panda/src/collide/collisionNode.h
  5. 4 4
      panda/src/cull/cullBinBackToFront.cxx
  6. 2 2
      panda/src/cull/cullBinBackToFront.h
  7. 4 4
      panda/src/cull/cullBinFixed.cxx
  8. 2 2
      panda/src/cull/cullBinFixed.h
  9. 4 4
      panda/src/cull/cullBinFrontToBack.cxx
  10. 2 2
      panda/src/cull/cullBinFrontToBack.h
  11. 6 6
      panda/src/cull/cullBinOcclusionTest.cxx
  12. 2 2
      panda/src/cull/cullBinOcclusionTest.h
  13. 4 4
      panda/src/cull/cullBinStateSorted.cxx
  14. 2 2
      panda/src/cull/cullBinStateSorted.h
  15. 2 2
      panda/src/cull/cullBinUnsorted.cxx
  16. 1 1
      panda/src/cull/cullBinUnsorted.h
  17. 1 1
      panda/src/cull/drawCullHandler.cxx
  18. 5 6
      panda/src/dgraph/dataGraphTraverser.cxx
  19. 3 1
      panda/src/dgraph/dataGraphTraverser.h
  20. 7 6
      panda/src/display/displayRegion.I
  21. 4 2
      panda/src/display/displayRegion.cxx
  22. 4 4
      panda/src/display/displayRegion.h
  23. 42 41
      panda/src/display/graphicsEngine.cxx
  24. 1 1
      panda/src/display/graphicsEngine.h
  25. 2 2
      panda/src/display/graphicsOutput.cxx
  26. 2 2
      panda/src/display/graphicsOutput.h
  27. 4 4
      panda/src/display/graphicsStateGuardian.cxx
  28. 2 2
      panda/src/display/graphicsStateGuardian.h
  29. 4 4
      panda/src/display/parasiteBuffer.cxx
  30. 2 2
      panda/src/display/parasiteBuffer.h
  31. 2 1
      panda/src/display/standardMunger.cxx
  32. 2 1
      panda/src/display/standardMunger.h
  33. 6 4
      panda/src/distort/projectionScreen.cxx
  34. 4 4
      panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx
  35. 2 2
      panda/src/dxgsg8/dxGraphicsStateGuardian8.h
  36. 4 4
      panda/src/dxgsg8/wdxGraphicsBuffer8.cxx
  37. 2 2
      panda/src/dxgsg8/wdxGraphicsBuffer8.h
  38. 2 2
      panda/src/dxgsg8/wdxGraphicsWindow8.cxx
  39. 4 4
      panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx
  40. 2 2
      panda/src/dxgsg9/dxGraphicsStateGuardian9.h
  41. 4 4
      panda/src/dxgsg9/wdxGraphicsBuffer9.cxx
  42. 2 2
      panda/src/dxgsg9/wdxGraphicsBuffer9.h
  43. 4 4
      panda/src/dxgsg9/wdxGraphicsWindow9.cxx
  44. 4 3
      panda/src/framework/pandaFramework.cxx
  45. 1 1
      panda/src/framework/pandaFramework.h
  46. 4 4
      panda/src/glstuff/glGraphicsBuffer_src.cxx
  47. 2 2
      panda/src/glstuff/glGraphicsBuffer_src.h
  48. 20 19
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  49. 4 3
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  50. 5 5
      panda/src/glxdisplay/glxGraphicsBuffer.cxx
  51. 2 2
      panda/src/glxdisplay/glxGraphicsBuffer.h
  52. 5 5
      panda/src/glxdisplay/glxGraphicsWindow.cxx
  53. 2 2
      panda/src/glxdisplay/glxGraphicsWindow.h
  54. 3 3
      panda/src/gobj/bufferResidencyTracker.cxx
  55. 2 2
      panda/src/gobj/bufferResidencyTracker.h
  56. 9 7
      panda/src/gobj/geom.I
  57. 11 11
      panda/src/gobj/geom.cxx
  58. 7 6
      panda/src/gobj/geom.h
  59. 7 6
      panda/src/gobj/geomMunger.cxx
  60. 4 2
      panda/src/gobj/geomMunger.h
  61. 6 4
      panda/src/gobj/geomPrimitive.cxx
  62. 2 1
      panda/src/gobj/geomPrimitive.h
  63. 2 3
      panda/src/gobj/geomVertexData.cxx
  64. 1 1
      panda/src/gobj/geomVertexData.h
  65. 17 12
      panda/src/gobj/geomVertexReader.I
  66. 11 6
      panda/src/gobj/geomVertexReader.h
  67. 16 12
      panda/src/gobj/geomVertexWriter.I
  68. 11 6
      panda/src/gobj/geomVertexWriter.h
  69. 10 10
      panda/src/gobj/preparedGraphicsObjects.cxx
  70. 3 2
      panda/src/gobj/preparedGraphicsObjects.h
  71. 6 5
      panda/src/grutil/multitexReducer.cxx
  72. 10 7
      panda/src/parametrics/ropeNode.cxx
  73. 3 2
      panda/src/parametrics/ropeNode.h
  74. 10 7
      panda/src/parametrics/sheetNode.cxx
  75. 3 2
      panda/src/parametrics/sheetNode.h
  76. 1 11
      panda/src/pgraph/cullBin.cxx
  77. 2 2
      panda/src/pgraph/cullBin.h
  78. 6 5
      panda/src/pgraph/cullResult.cxx
  79. 1 1
      panda/src/pgraph/cullResult.h
  80. 11 0
      panda/src/pgraph/cullTraverser.I
  81. 9 6
      panda/src/pgraph/cullTraverser.cxx
  82. 3 1
      panda/src/pgraph/cullTraverser.h
  83. 3 3
      panda/src/pgraph/cullTraverserData.I
  84. 1 1
      panda/src/pgraph/cullTraverserData.h
  85. 48 24
      panda/src/pgraph/cullableObject.cxx
  86. 14 10
      panda/src/pgraph/geomNode.cxx
  87. 3 2
      panda/src/pgraph/geomNode.h
  88. 58 55
      panda/src/pgraph/nodePath.I
  89. 167 154
      panda/src/pgraph/nodePath.cxx
  90. 77 60
      panda/src/pgraph/nodePath.h
  91. 19 18
      panda/src/pgraph/nodePathComponent.cxx
  92. 7 7
      panda/src/pgraph/nodePathComponent.h
  93. 118 56
      panda/src/pgraph/pandaNode.I
  94. 179 167
      panda/src/pgraph/pandaNode.cxx
  95. 90 74
      panda/src/pgraph/pandaNode.h
  96. 2 2
      panda/src/pgraph/planeNode.cxx
  97. 1 1
      panda/src/pgraph/planeNode.h
  98. 2 2
      panda/src/pgraph/portalNode.cxx
  99. 1 1
      panda/src/pgraph/portalNode.h
  100. 8 6
      panda/src/pgraph/workingNodePath.cxx

+ 2 - 1
panda/src/char/character.cxx

@@ -277,7 +277,8 @@ copy_joints(PartGroup *copy, PartGroup *orig) {
 //               override this function.
 ////////////////////////////////////////////////////////////////////
 void Character::
-r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map) {
+r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map,
+                Thread *current_thread) {
   // We assume there will be no instancing going on below the
   // Character node.  If there is, too bad; it will get flattened out.
 

+ 2 - 1
panda/src/char/character.h

@@ -82,7 +82,8 @@ private:
   typedef pmap<const VertexTransform *, PT(JointVertexTransform) > GeomJointMap;
   typedef pmap<const VertexSlider *, PT(CharacterVertexSlider) > GeomSliderMap;
 
-  virtual void r_copy_children(const PandaNode *from, InstanceMap &inst_map);
+  virtual void r_copy_children(const PandaNode *from, InstanceMap &inst_map,
+                               Thread *current_thread);
   void fill_joint_map(JointMap &joint_map, PartGroup *copy, PartGroup *orig);
   void r_copy_char(PandaNode *dest, const PandaNode *source,
                    const Character *from, NodeMap &node_map,

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

@@ -371,9 +371,9 @@ get_collide_geom() const {
 //               thing.
 ////////////////////////////////////////////////////////////////////
 PT(BoundingVolume) CollisionNode::
-compute_internal_bounds(int pipeline_stage) const {
+compute_internal_bounds(int pipeline_stage, Thread *current_thread) const {
   // First, get ourselves a fresh, empty bounding volume.
-  PT(BoundingVolume) bound = PandaNode::compute_internal_bounds(pipeline_stage);
+  PT(BoundingVolume) bound = PandaNode::compute_internal_bounds(pipeline_stage, current_thread);
   nassertr(bound != (BoundingVolume *)NULL, bound);
 
   // Now actually compute the bounding volume by putting it around all

+ 1 - 1
panda/src/collide/collisionNode.h

@@ -75,7 +75,7 @@ PUBLISHED:
   INLINE static CollideMask get_default_collide_mask();
 
 protected:
-  virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage) const;
+  virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage, Thread *current_thread) const;
 
 private:
   CPT(RenderState) get_last_pos_state();

+ 4 - 4
panda/src/cull/cullBinBackToFront.cxx

@@ -59,7 +59,7 @@ make_bin(const string &name, GraphicsStateGuardianBase *gsg) {
 //               the bin for rendering.
 ////////////////////////////////////////////////////////////////////
 void CullBinBackToFront::
-add_object(CullableObject *object) {
+add_object(CullableObject *object, Thread *current_thread) {
   // Determine the center of the bounding volume.
   CPT(BoundingVolume) volume = object->_geom->get_bounds();
 
@@ -86,8 +86,8 @@ add_object(CullableObject *object) {
 //               draw.
 ////////////////////////////////////////////////////////////////////
 void CullBinBackToFront::
-finish_cull(SceneSetup *) {
-  PStatTimer timer(_cull_this_pcollector);
+finish_cull(SceneSetup *, Thread *current_thread) {
+  PStatTimer timer(_cull_this_pcollector, current_thread);
   sort(_objects.begin(), _objects.end());
 }
 
@@ -99,7 +99,7 @@ finish_cull(SceneSetup *) {
 ////////////////////////////////////////////////////////////////////
 void CullBinBackToFront::
 draw(Thread *current_thread) {
-  PStatTimer timer(_draw_this_pcollector);
+  PStatTimer timer(_draw_this_pcollector, current_thread);
   Objects::const_iterator oi;
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     CullableObject *object = (*oi)._object;

+ 2 - 2
panda/src/cull/cullBinBackToFront.h

@@ -43,8 +43,8 @@ public:
   static CullBin *make_bin(const string &name, GraphicsStateGuardianBase *gsg);
   
 
-  virtual void add_object(CullableObject *object);
-  virtual void finish_cull(SceneSetup *scene_setup);
+  virtual void add_object(CullableObject *object, Thread *current_thread);
+  virtual void finish_cull(SceneSetup *scene_setup, Thread *current_thread);
   virtual void draw(Thread *current_thread);
 
 private:

+ 4 - 4
panda/src/cull/cullBinFixed.cxx

@@ -59,7 +59,7 @@ make_bin(const string &name, GraphicsStateGuardianBase *gsg) {
 //               the bin for rendering.
 ////////////////////////////////////////////////////////////////////
 void CullBinFixed::
-add_object(CullableObject *object) {
+add_object(CullableObject *object, Thread *current_thread) {
   int draw_order = object->_state->get_draw_order();
   _objects.push_back(ObjectData(object, draw_order));
 }
@@ -74,8 +74,8 @@ add_object(CullableObject *object) {
 //               draw.
 ////////////////////////////////////////////////////////////////////
 void CullBinFixed::
-finish_cull(SceneSetup *) {
-  PStatTimer timer(_cull_this_pcollector);
+finish_cull(SceneSetup *, Thread *current_thread) {
+  PStatTimer timer(_cull_this_pcollector, current_thread);
   stable_sort(_objects.begin(), _objects.end());
 }
 
@@ -87,7 +87,7 @@ finish_cull(SceneSetup *) {
 ////////////////////////////////////////////////////////////////////
 void CullBinFixed::
 draw(Thread *current_thread) {
-  PStatTimer timer(_draw_this_pcollector);
+  PStatTimer timer(_draw_this_pcollector, current_thread);
   Objects::const_iterator oi;
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     CullableObject *object = (*oi)._object;

+ 2 - 2
panda/src/cull/cullBinFixed.h

@@ -45,8 +45,8 @@ public:
 
   static CullBin *make_bin(const string &name, GraphicsStateGuardianBase *gsg);
 
-  virtual void add_object(CullableObject *object);
-  virtual void finish_cull(SceneSetup *scene_setup);
+  virtual void add_object(CullableObject *object, Thread *current_thread);
+  virtual void finish_cull(SceneSetup *scene_setup, Thread *current_thread);
   virtual void draw(Thread *current_thread);
 
 private:

+ 4 - 4
panda/src/cull/cullBinFrontToBack.cxx

@@ -59,7 +59,7 @@ make_bin(const string &name, GraphicsStateGuardianBase *gsg) {
 //               the bin for rendering.
 ////////////////////////////////////////////////////////////////////
 void CullBinFrontToBack::
-add_object(CullableObject *object) {
+add_object(CullableObject *object, Thread *current_thread) {
   // Determine the center of the bounding volume.
   CPT(BoundingVolume) volume = object->_geom->get_bounds();
 
@@ -86,8 +86,8 @@ add_object(CullableObject *object) {
 //               draw.
 ////////////////////////////////////////////////////////////////////
 void CullBinFrontToBack::
-finish_cull(SceneSetup *) {
-  PStatTimer timer(_cull_this_pcollector);
+finish_cull(SceneSetup *, Thread *current_thread) {
+  PStatTimer timer(_cull_this_pcollector, current_thread);
   sort(_objects.begin(), _objects.end());
 }
 
@@ -99,7 +99,7 @@ finish_cull(SceneSetup *) {
 ////////////////////////////////////////////////////////////////////
 void CullBinFrontToBack::
 draw(Thread *current_thread) {
-  PStatTimer timer(_draw_this_pcollector);
+  PStatTimer timer(_draw_this_pcollector, current_thread);
   Objects::const_iterator oi;
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     CullableObject *object = (*oi)._object;

+ 2 - 2
panda/src/cull/cullBinFrontToBack.h

@@ -43,8 +43,8 @@ public:
 
   static CullBin *make_bin(const string &name, GraphicsStateGuardianBase *gsg);
 
-  virtual void add_object(CullableObject *object);
-  virtual void finish_cull(SceneSetup *scene_setup);
+  virtual void add_object(CullableObject *object, Thread *current_thread);
+  virtual void finish_cull(SceneSetup *scene_setup, Thread *current_thread);
   virtual void draw(Thread *current_thread);
 
 private:

+ 6 - 6
panda/src/cull/cullBinOcclusionTest.cxx

@@ -116,7 +116,7 @@ make_next() const {
 //               the bin for rendering.
 ////////////////////////////////////////////////////////////////////
 void CullBinOcclusionTest::
-add_object(CullableObject *object) {
+add_object(CullableObject *object, Thread *current_thread) {
   // Determine the world-space bounding sphere for the object.
   CPT(BoundingVolume) volume = object->_geom->get_bounds();
   if (volume->is_empty()) {
@@ -151,8 +151,8 @@ add_object(CullableObject *object) {
 //               draw.
 ////////////////////////////////////////////////////////////////////
 void CullBinOcclusionTest::
-finish_cull(SceneSetup *scene_setup) {
-  PStatTimer timer(_cull_this_pcollector);
+finish_cull(SceneSetup *scene_setup, Thread *current_thread) {
+  PStatTimer timer(_cull_this_pcollector, current_thread);
 
   // Now we have a loose list of objects that are to be rendered.
   // We'd rather have them in an octree, which has much better
@@ -196,7 +196,7 @@ finish_cull(SceneSetup *scene_setup) {
 ////////////////////////////////////////////////////////////////////
 void CullBinOcclusionTest::
 draw(Thread *current_thread) {
-  PStatTimer timer(_draw_this_pcollector);
+  PStatTimer timer(_draw_this_pcollector, current_thread);
 
   // We'll want to know the near plane distance.
   _near_distance = _gsg->get_scene()->get_lens()->get_near();
@@ -494,7 +494,7 @@ occlusion_test(CullBinOcclusionTest &bin, Thread *current_thread) {
   
   CPT(Geom) viz = get_octree_solid_test();
   CPT(GeomVertexData) munged_data = viz->get_vertex_data();
-  munger->munge_geom(viz, munged_data);
+  munger->munge_geom(viz, munged_data, current_thread);
   
   bin._gsg->set_state_and_transform(state, internal_transform);
 
@@ -632,7 +632,7 @@ draw_wireframe(CullBinOcclusionTest &bin, Thread *current_thread) {
   
   CPT(Geom) viz = get_octree_wireframe_viz();
   CPT(GeomVertexData) munged_data = viz->get_vertex_data();
-  munger->munge_geom(viz, munged_data);
+  munger->munge_geom(viz, munged_data, current_thread);
   
   bin._gsg->set_state_and_transform(state, internal_transform);
   viz->draw(bin._gsg, munger, munged_data, current_thread);

+ 2 - 2
panda/src/cull/cullBinOcclusionTest.h

@@ -57,8 +57,8 @@ public:
   static CullBin *make_bin(const string &name, GraphicsStateGuardianBase *gsg);
   virtual PT(CullBin) make_next() const;
 
-  virtual void add_object(CullableObject *object);
-  virtual void finish_cull(SceneSetup *scene_setup);
+  virtual void add_object(CullableObject *object, Thread *current_thread);
+  virtual void finish_cull(SceneSetup *scene_setup, Thread *current_thread);
   virtual void draw(Thread *current_thread);
 
 private:

+ 4 - 4
panda/src/cull/cullBinStateSorted.cxx

@@ -58,7 +58,7 @@ make_bin(const string &name, GraphicsStateGuardianBase *gsg) {
 //               the bin for rendering.
 ////////////////////////////////////////////////////////////////////
 void CullBinStateSorted::
-add_object(CullableObject *object) {
+add_object(CullableObject *object, Thread *current_thread) {
   _objects.push_back(ObjectData(object));
 }
 
@@ -72,8 +72,8 @@ add_object(CullableObject *object) {
 //               draw.
 ////////////////////////////////////////////////////////////////////
 void CullBinStateSorted::
-finish_cull(SceneSetup *) {
-  PStatTimer timer(_cull_this_pcollector);
+finish_cull(SceneSetup *, Thread *current_thread) {
+  PStatTimer timer(_cull_this_pcollector, current_thread);
   sort(_objects.begin(), _objects.end());
 }
 
@@ -86,7 +86,7 @@ finish_cull(SceneSetup *) {
 ////////////////////////////////////////////////////////////////////
 void CullBinStateSorted::
 draw(Thread *current_thread) {
-  PStatTimer timer(_draw_this_pcollector);
+  PStatTimer timer(_draw_this_pcollector, current_thread);
   Objects::const_iterator oi;
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     CullableObject *object = (*oi)._object;

+ 2 - 2
panda/src/cull/cullBinStateSorted.h

@@ -47,8 +47,8 @@ public:
 
   static CullBin *make_bin(const string &name, GraphicsStateGuardianBase *gsg);
 
-  virtual void add_object(CullableObject *object);
-  virtual void finish_cull(SceneSetup *scene_setup);
+  virtual void add_object(CullableObject *object, Thread *current_thread);
+  virtual void finish_cull(SceneSetup *scene_setup, Thread *current_thread);
   virtual void draw(Thread *current_thread);
 
 private:

+ 2 - 2
panda/src/cull/cullBinUnsorted.cxx

@@ -55,7 +55,7 @@ make_bin(const string &name, GraphicsStateGuardianBase *gsg) {
 //               the bin for rendering.
 ////////////////////////////////////////////////////////////////////
 void CullBinUnsorted::
-add_object(CullableObject *object) {
+add_object(CullableObject *object, Thread *current_thread) {
   _objects.push_back(object);
 }
 
@@ -67,7 +67,7 @@ add_object(CullableObject *object) {
 ////////////////////////////////////////////////////////////////////
 void CullBinUnsorted::
 draw(Thread *current_thread) {
-  PStatTimer timer(_draw_this_pcollector);
+  PStatTimer timer(_draw_this_pcollector, current_thread);
   Objects::iterator oi;
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     CullableObject *object = (*oi);

+ 1 - 1
panda/src/cull/cullBinUnsorted.h

@@ -38,7 +38,7 @@ public:
 
   static CullBin *make_bin(const string &name, GraphicsStateGuardianBase *gsg);
 
-  virtual void add_object(CullableObject *object);
+  virtual void add_object(CullableObject *object, Thread *current_thread);
   virtual void draw(Thread *current_thread);
 
 private:

+ 1 - 1
panda/src/cull/drawCullHandler.cxx

@@ -38,6 +38,6 @@ record_object(CullableObject *object, const CullTraverser *traverser) {
   object->munge_geom(_gsg, _gsg->get_geom_munger(object->_state), traverser);
 
   // And draw the object, then dispense with it.
-  draw(object, _gsg, Thread::get_current_thread());
+  draw(object, _gsg, traverser->get_current_thread());
   delete object;
 }

+ 5 - 6
panda/src/dgraph/dataGraphTraverser.cxx

@@ -47,7 +47,7 @@ set_data(int parent_index, const DataNodeTransmit &data) {
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 DataGraphTraverser::
-DataGraphTraverser() {
+DataGraphTraverser(Thread *current_thread) : _current_thread(current_thread) {
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -69,9 +69,8 @@ void DataGraphTraverser::
 traverse(PandaNode *node) {
   if (node->is_of_type(DataNode::get_class_type())) {
     DataNode *data_node = DCAST(DataNode, node);
-    int num_parents = data_node->get_num_parents();
     // We must start the traversal at the root of the graph.
-    nassertv(num_parents == 0);
+    nassertv(data_node->get_num_parents(_current_thread) == 0);
 
     r_transmit(data_node, (DataNodeTransmit *)NULL);
 
@@ -91,7 +90,7 @@ traverse(PandaNode *node) {
 ////////////////////////////////////////////////////////////////////
 void DataGraphTraverser::
 traverse_below(PandaNode *node, const DataNodeTransmit &output) {
-  PandaNode::Children cr = node->get_children();
+  PandaNode::Children cr = node->get_children(_current_thread);
   int num_children = cr.get_num_children();
 
   for (int i = 0; i < num_children; i++) {
@@ -101,7 +100,7 @@ traverse_below(PandaNode *node, const DataNodeTransmit &output) {
       // If it's a DataNode-type child, we need to pass it the data.
       // Maybe it has only one parent, and can accept the data
       // immediately.
-      int num_parents = data_node->get_num_parents();
+      int num_parents = data_node->get_num_parents(_current_thread);
       if (num_parents == 1) {
         // The easy, common case: only one parent.  We make our output
         // into a one-element array of inputs by turning it into a
@@ -112,7 +111,7 @@ traverse_below(PandaNode *node, const DataNodeTransmit &output) {
         // instances together, meaning we must hold onto this node
         // until we have reached it through all paths.
         CollectedData &collected_data = _multipass_data[data_node];
-        int parent_index = data_node->find_parent(node);
+        int parent_index = data_node->find_parent(node, _current_thread);
         nassertv(parent_index != -1);
 
         collected_data.set_data(parent_index, output);

+ 3 - 1
panda/src/dgraph/dataGraphTraverser.h

@@ -38,7 +38,7 @@ class PandaNode;
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA DataGraphTraverser {
 PUBLISHED:
-  DataGraphTraverser();
+  DataGraphTraverser(Thread *current_thread);
   ~DataGraphTraverser();
 
   void traverse(PandaNode *node);
@@ -50,6 +50,8 @@ private:
 
   typedef pvector<DataNodeTransmit> DataVector;
 
+  Thread *_current_thread;
+
   class CollectedData {
   public:
     INLINE CollectedData();

+ 7 - 6
panda/src/display/displayRegion.I

@@ -305,8 +305,9 @@ get_pixel_height() const {
 //               to all upstream pipeline stages.
 ////////////////////////////////////////////////////////////////////
 INLINE void DisplayRegion::
-set_cull_result(CullResult *cull_result, SceneSetup *scene_setup) {
-  CDCullWriter cdata(_cycler_cull, true);
+set_cull_result(CullResult *cull_result, SceneSetup *scene_setup,
+                Thread *current_thread) {
+  CDCullWriter cdata(_cycler_cull, true, current_thread);
   cdata->_cull_result = cull_result;
   cdata->_scene_setup = scene_setup;
 }
@@ -321,8 +322,8 @@ set_cull_result(CullResult *cull_result, SceneSetup *scene_setup) {
 //               directly.
 ////////////////////////////////////////////////////////////////////
 INLINE CullResult *DisplayRegion::
-get_cull_result() const {
-  CDCullReader cdata(_cycler_cull);
+get_cull_result(Thread *current_thread) const {
+  CDCullReader cdata(_cycler_cull, current_thread);
   return cdata->_cull_result;
 }
 
@@ -336,8 +337,8 @@ get_cull_result() const {
 //               directly.
 ////////////////////////////////////////////////////////////////////
 INLINE SceneSetup *DisplayRegion::
-get_scene_setup() const {
-  CDCullReader cdata(_cycler_cull);
+get_scene_setup(Thread *current_thread) const {
+  CDCullReader cdata(_cycler_cull, current_thread);
   return cdata->_scene_setup;
 }
 

+ 4 - 2
panda/src/display/displayRegion.cxx

@@ -470,13 +470,15 @@ save_screenshot(const Filename &filename, const string &image_comment) {
 ////////////////////////////////////////////////////////////////////
 bool DisplayRegion::
 get_screenshot(PNMImage &image) {
+  Thread *current_thread = Thread::get_current_thread();
+
   GraphicsOutput *window = get_window();
   nassertr(window != (GraphicsOutput *)NULL, false);
   
   GraphicsStateGuardian *gsg = window->get_gsg();
   nassertr(gsg != (GraphicsStateGuardian *)NULL, false);
   
-  if (!window->begin_frame(GraphicsOutput::FM_refresh)) {
+  if (!window->begin_frame(GraphicsOutput::FM_refresh, current_thread)) {
     return false;
   }
 
@@ -489,7 +491,7 @@ get_screenshot(PNMImage &image) {
     return false;
   }
   
-  window->end_frame(GraphicsOutput::FM_refresh);
+  window->end_frame(GraphicsOutput::FM_refresh, current_thread);
   
   if (!tex->store(image)) {
     return false;

+ 4 - 4
panda/src/display/displayRegion.h

@@ -119,10 +119,10 @@ PUBLISHED:
   bool get_screenshot(PNMImage &image);
 
 public:
-  INLINE void set_cull_result(
-    CullResult *cull_result, SceneSetup *scene_setup);
-  INLINE CullResult *get_cull_result() const;
-  INLINE SceneSetup *get_scene_setup() const;
+  INLINE void set_cull_result(CullResult *cull_result, SceneSetup *scene_setup,
+                              Thread *current_thread);
+  INLINE CullResult *get_cull_result(Thread *current_thread) const;
+  INLINE SceneSetup *get_scene_setup(Thread *current_thread) const;
 
 private:
   class CData;

+ 42 - 41
panda/src/display/graphicsEngine.cxx

@@ -478,7 +478,7 @@ remove_all_windows() {
 
   _app.do_close(this, current_thread);
   _app.do_pending(this, current_thread);
-  terminate_threads();
+  terminate_threads(current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -623,7 +623,7 @@ render_frame() {
   // Grab each thread's mutex again after all windows have flipped,
   // and wait for the thread to finish.
   {
-    PStatTimer timer(_wait_pcollector);
+    PStatTimer timer(_wait_pcollector, current_thread);
     Threads::const_iterator ti;
     for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
       RenderThread *thread = (*ti).second;
@@ -652,7 +652,7 @@ render_frame() {
   // between frames.
   ObjectDeletor *deletor = ObjectDeletor::get_global_ptr();
   if (deletor != (ObjectDeletor *)NULL) {
-    PStatTimer timer(_delete_pcollector);
+    PStatTimer timer(_delete_pcollector, current_thread);
     deletor->flush();
   }
   
@@ -664,13 +664,13 @@ render_frame() {
   // Now cycle the pipeline and officially begin the next frame.
 #ifdef THREADED_PIPELINE
   {
-    PStatTimer timer(_cycle_pcollector);
+    PStatTimer timer(_cycle_pcollector, current_thread);
     _pipeline->cycle();
   }
 #endif  // THREADED_PIPELINE
 
-  global_clock->tick();
-  if (global_clock->check_errors()) {
+  global_clock->tick(current_thread);
+  if (global_clock->check_errors(current_thread)) {
     throw_event("clock_error");
   }
 
@@ -735,7 +735,7 @@ render_frame() {
   if (yield_timeslice) { 
     // Nap for a moment to yield the timeslice, to be polite to other
     // running applications.
-    PStatTimer timer(_yield_pcollector);
+    PStatTimer timer(_yield_pcollector, current_thread);
     struct timeval tv;
     tv.tv_sec = 0;
     tv.tv_usec = 0;
@@ -776,7 +776,7 @@ open_windows() {
     _app.do_windows(this, current_thread);
     _app.do_pending(this, current_thread);
 
-    PStatTimer timer(_wait_pcollector);
+    PStatTimer timer(_wait_pcollector, current_thread);
     Threads::const_iterator ti;
     for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
       RenderThread *thread = (*ti).second;
@@ -964,13 +964,13 @@ set_window_sort(GraphicsOutput *window, int sort) {
 void GraphicsEngine::
 cull_and_draw_together(const GraphicsEngine::Windows &wlist,
                        Thread *current_thread) {
-  PStatTimer timer(_cull_pcollector);
+  PStatTimer timer(_cull_pcollector, current_thread);
 
   Windows::const_iterator wi;
   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
     GraphicsOutput *win = (*wi);
     if (win->is_active() && win->get_gsg()->is_active()) {
-      if (win->begin_frame(GraphicsOutput::FM_render)) {
+      if (win->begin_frame(GraphicsOutput::FM_render, current_thread)) {
         win->clear(current_thread);
       
         int num_display_regions = win->get_num_active_display_regions();
@@ -980,16 +980,16 @@ cull_and_draw_together(const GraphicsEngine::Windows &wlist,
             cull_and_draw_together(win, dr, current_thread);
           }
         }
-        win->end_frame(GraphicsOutput::FM_render);
+        win->end_frame(GraphicsOutput::FM_render, current_thread);
 
         if (_auto_flip) {
           if (win->flip_ready()) {
             {
-              PStatTimer timer(GraphicsEngine::_flip_begin_pcollector);
+              PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
               win->begin_flip();
             }
             {
-              PStatTimer timer(GraphicsEngine::_flip_end_pcollector);
+              PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
               win->end_flip();
             }
           }
@@ -1052,7 +1052,7 @@ cull_and_draw_together(GraphicsOutput *win, DisplayRegion *dr,
 ////////////////////////////////////////////////////////////////////
 void GraphicsEngine::
 cull_to_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
-  PStatTimer timer(_cull_pcollector);
+  PStatTimer timer(_cull_pcollector, current_thread);
 
   // Keep track of the cameras we have already used in this thread to
   // render DisplayRegions.
@@ -1088,8 +1088,9 @@ cull_to_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
             // result will be the same, so just use the result from
             // the other DisplayRegion.
             DisplayRegion *other_dr = (*aci).second;
-            dr->set_cull_result(other_dr->get_cull_result(),
-                                setup_scene(win->get_gsg(), dr_reader));
+            dr->set_cull_result(other_dr->get_cull_result(current_thread),
+                                setup_scene(win->get_gsg(), dr_reader),
+                                current_thread);
           }
 
           if (dr_reader != (DisplayRegionPipelineReader *)NULL) {
@@ -1115,8 +1116,8 @@ cull_to_bins(GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread) {
   PT(CullResult) cull_result;
   PT(SceneSetup) scene_setup;
   {
-    PStatTimer timer(_cull_setup_pcollector);
-    cull_result = dr->get_cull_result();
+    PStatTimer timer(_cull_setup_pcollector, current_thread);
+    cull_result = dr->get_cull_result(current_thread);
     if (cull_result != (CullResult *)NULL) {
       cull_result = cull_result->make_next();
     } else {
@@ -1131,10 +1132,10 @@ cull_to_bins(GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread) {
     do_cull(&cull_handler, scene_setup, gsg, current_thread);
 
     {
-      PStatTimer timer(_cull_sort_pcollector);
-      cull_result->finish_cull(scene_setup);
+      PStatTimer timer(_cull_sort_pcollector, current_thread);
+      cull_result->finish_cull(scene_setup, current_thread);
       // Save the results for next frame.
-      dr->set_cull_result(cull_result, scene_setup);
+      dr->set_cull_result(cull_result, scene_setup, current_thread);
     }
   }
 }
@@ -1154,7 +1155,7 @@ draw_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
     GraphicsOutput *win = (*wi);
     if (win->is_active() && win->get_gsg()->is_active()) {
-      if (win->begin_frame(GraphicsOutput::FM_render)) {
+      if (win->begin_frame(GraphicsOutput::FM_render, current_thread)) {
         win->clear(current_thread);
       
         int num_display_regions = win->get_num_active_display_regions();
@@ -1164,16 +1165,16 @@ draw_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
             draw_bins(win, dr, current_thread);
           }
         }
-        win->end_frame(GraphicsOutput::FM_render);
+        win->end_frame(GraphicsOutput::FM_render, current_thread);
 
         if (_auto_flip) {
           if (win->flip_ready()) {
             {
-              PStatTimer timer(GraphicsEngine::_flip_begin_pcollector);
+              PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
               win->begin_flip();
             }
             {
-              PStatTimer timer(GraphicsEngine::_flip_end_pcollector);
+              PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
               win->end_flip();
             }
           }
@@ -1195,8 +1196,8 @@ draw_bins(GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread) {
   GraphicsStateGuardian *gsg = win->get_gsg();
   nassertv(gsg != (GraphicsStateGuardian *)NULL);
 
-  PT(CullResult) cull_result = dr->get_cull_result();
-  PT(SceneSetup) scene_setup = dr->get_scene_setup();
+  PT(CullResult) cull_result = dr->get_cull_result(current_thread);
+  PT(SceneSetup) scene_setup = dr->get_scene_setup(current_thread);
   if (cull_result != (CullResult *)NULL && scene_setup != (SceneSetup *)NULL) {
     do_draw(cull_result, scene_setup, win, dr, current_thread);
   }
@@ -1214,8 +1215,8 @@ make_contexts(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
   Windows::const_iterator wi;
   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
     GraphicsOutput *win = (*wi);
-    if (win->begin_frame(GraphicsOutput::FM_refresh)) {
-      win->end_frame(GraphicsOutput::FM_refresh);
+    if (win->begin_frame(GraphicsOutput::FM_refresh, current_thread)) {
+      win->end_frame(GraphicsOutput::FM_refresh, current_thread);
     }
   }
 }
@@ -1249,14 +1250,14 @@ flip_windows(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
     GraphicsOutput *win = (*wi);
     if (win->flip_ready()) {
-      PStatTimer timer(GraphicsEngine::_flip_begin_pcollector);
+      PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
       win->begin_flip();
     }
   }
   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
     GraphicsOutput *win = (*wi);
     if (win->flip_ready()) {
-      PStatTimer timer(GraphicsEngine::_flip_end_pcollector);
+      PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
       win->end_flip();
     }
   }
@@ -1273,7 +1274,7 @@ do_sync_frame(Thread *current_thread) {
   nassertv(_lock.debug_is_locked());
 
   // Statistics
-  PStatTimer timer(_sync_pcollector);
+  PStatTimer timer(_sync_pcollector, current_thread);
 
   nassertv(_flip_state == FS_draw);
 
@@ -1300,7 +1301,7 @@ do_flip_frame(Thread *current_thread) {
   nassertv(_lock.debug_is_locked());
 
   // Statistics
-  PStatTimer timer(_flip_pcollector);
+  PStatTimer timer(_flip_pcollector, current_thread);
 
   nassertv(_flip_state == FS_draw || _flip_state == FS_sync);
 
@@ -1308,7 +1309,7 @@ do_flip_frame(Thread *current_thread) {
   // necessary.  Grabbing the mutex (and waiting for TS_wait) should
   // achieve that.
   {
-    PStatTimer timer(_wait_pcollector);
+    PStatTimer timer(_wait_pcollector, current_thread);
     Threads::const_iterator ti;
     for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
       RenderThread *thread = (*ti).second;
@@ -1347,7 +1348,7 @@ do_flip_frame(Thread *current_thread) {
 ////////////////////////////////////////////////////////////////////
 PT(SceneSetup) GraphicsEngine::
 setup_scene(GraphicsStateGuardian *gsg, DisplayRegionPipelineReader *dr) {
-  PStatTimer timer(_cull_setup_pcollector);
+  PStatTimer timer(_cull_setup_pcollector, dr->get_current_thread());
 
   GraphicsOutput *window = dr->get_window();
   // The window pointer shouldn't be NULL, since we presumably got to
@@ -1431,7 +1432,7 @@ setup_scene(GraphicsStateGuardian *gsg, DisplayRegionPipelineReader *dr) {
 void GraphicsEngine::
 do_cull(CullHandler *cull_handler, SceneSetup *scene_setup,
         GraphicsStateGuardian *gsg, Thread *current_thread) {
-  CullTraverser trav(gsg);
+  CullTraverser trav(gsg, current_thread);
   trav.set_cull_handler(cull_handler);
   trav.set_depth_offset_decals(depth_offset_decals && gsg->depth_offset_decals());
   trav.set_scene(scene_setup);
@@ -1471,7 +1472,7 @@ void GraphicsEngine::
 do_draw(CullResult *cull_result, SceneSetup *scene_setup,
         GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread) {
   // Statistics
-  PStatTimer timer(_draw_pcollector);
+  PStatTimer timer(_draw_pcollector, current_thread);
 
   DisplayRegionPipelineReader *dr_reader = 
     new DisplayRegionPipelineReader(dr, current_thread);
@@ -1662,12 +1663,12 @@ do_resort_windows() {
 //               them to clean up.
 ////////////////////////////////////////////////////////////////////
 void GraphicsEngine::
-terminate_threads() {
+terminate_threads(Thread *current_thread) {
   MutexHolder holder(_lock);
 
   // We spend almost our entire time in this method just waiting for
   // threads.  Time it appropriately.
-  PStatTimer timer(_wait_pcollector);
+  PStatTimer timer(_wait_pcollector, current_thread);
   
   // First, wait for all the threads to finish their current frame.
   // Grabbing the mutex should achieve that.
@@ -1903,7 +1904,7 @@ resort_windows() {
 ////////////////////////////////////////////////////////////////////
 void GraphicsEngine::WindowRenderer::
 do_frame(GraphicsEngine *engine, Thread *current_thread) {
-  PStatTimer timer(engine->_do_frame_pcollector);
+  PStatTimer timer(engine->_do_frame_pcollector, current_thread);
   MutexHolder holder(_wl_lock);
 
   do_callbacks(CB_pre_frame);
@@ -2165,7 +2166,7 @@ thread_main() {
     _cv_done.signal();
 
     {
-      PStatTimer timer(_wait_pcollector);
+      PStatTimer timer(_wait_pcollector, current_thread);
       _cv_start.wait();
     }
   }

+ 1 - 1
panda/src/display/graphicsEngine.h

@@ -179,7 +179,7 @@ private:
                      const GraphicsThreadingModel &threading_model);
   void do_remove_window(GraphicsOutput *window, Thread *current_thread);
   void do_resort_windows();
-  void terminate_threads();
+  void terminate_threads(Thread *current_thread);
 
 #ifdef DO_PSTATS
   typedef map<TypeHandle, PStatCollector> CyclerTypeCounters;

+ 2 - 2
panda/src/display/graphicsOutput.cxx

@@ -914,7 +914,7 @@ reset_window(bool swapchain) {
 //               should be skipped.
 ////////////////////////////////////////////////////////////////////
 bool GraphicsOutput::
-begin_frame(FrameMode mode) {
+begin_frame(FrameMode mode, Thread *current_thread) {
   return false;
 }
 
@@ -926,7 +926,7 @@ begin_frame(FrameMode mode) {
 //               should do whatever finalization is required.
 ////////////////////////////////////////////////////////////////////
 void GraphicsOutput::
-end_frame(FrameMode mode) {
+end_frame(FrameMode mode, Thread *current_thread) {
 }
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 2
panda/src/display/graphicsOutput.h

@@ -209,8 +209,8 @@ public:
   // thread other than the draw thread.  These methods are normally
   // called by the GraphicsEngine.
   void clear(Thread *current_thread);
-  virtual bool begin_frame(FrameMode mode);
-  virtual void end_frame(FrameMode mode);
+  virtual bool begin_frame(FrameMode mode, Thread *current_thread);
+  virtual void end_frame(FrameMode mode, Thread *current_thread);
 
   // These entry points have been removed. Use begin_frame/end_frame instead.
   //  virtual void begin_render_texture();

+ 4 - 4
panda/src/display/graphicsStateGuardian.cxx

@@ -1015,8 +1015,8 @@ prepare_lens() {
 //               be called).
 ////////////////////////////////////////////////////////////////////
 bool GraphicsStateGuardian::
-begin_frame() {
-  _prepared_objects->begin_frame(this);
+begin_frame(Thread *current_thread) {
+  _prepared_objects->begin_frame(this, current_thread);
 
 #ifdef DO_PSTATS
   // For Pstats to track our current texture memory usage, we have to
@@ -1121,8 +1121,8 @@ end_scene() {
 //               rendering the frame, and before the window flips.
 ////////////////////////////////////////////////////////////////////
 void GraphicsStateGuardian::
-end_frame() {
-  _prepared_objects->end_frame();
+end_frame(Thread *current_thread) {
+  _prepared_objects->end_frame(current_thread);
 
   // Flush any PStatCollectors.
   _data_transferred_pcollector.flush_level();

+ 2 - 2
panda/src/display/graphicsStateGuardian.h

@@ -181,10 +181,10 @@ public:
   virtual CPT(TransformState) calc_projection_mat(const Lens *lens);
   virtual bool prepare_lens();
 
-  virtual bool begin_frame();
+  virtual bool begin_frame(Thread *current_thread);
   virtual bool begin_scene();
   virtual void end_scene();
-  virtual void end_frame();
+  virtual void end_frame(Thread *current_thread);
 
   void set_current_properties(FrameBufferProperties *properties);
   

+ 4 - 4
panda/src/display/parasiteBuffer.cxx

@@ -107,10 +107,10 @@ get_host() {
 //               should be skipped.
 ////////////////////////////////////////////////////////////////////
 bool ParasiteBuffer::
-begin_frame(FrameMode mode) {
+begin_frame(FrameMode mode, Thread *current_thread) {
   begin_frame_spam();
 
-  if (!_host->begin_frame(FM_parasite)) {
+  if (!_host->begin_frame(FM_parasite, current_thread)) {
     return false;
   }
 
@@ -134,7 +134,7 @@ begin_frame(FrameMode mode) {
 //               should do whatever finalization is required.
 ////////////////////////////////////////////////////////////////////
 void ParasiteBuffer::
-end_frame(FrameMode mode) {
+end_frame(FrameMode mode, Thread *current_thread) {
   end_frame_spam();
 
   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
@@ -143,7 +143,7 @@ end_frame(FrameMode mode) {
     return;
   }
 
-  _host->end_frame(FM_parasite);
+  _host->end_frame(FM_parasite, current_thread);
   
   if (mode == FM_render) {
     for (int i=0; i<count_textures(); i++) {

+ 2 - 2
panda/src/display/parasiteBuffer.h

@@ -63,8 +63,8 @@ PUBLISHED:
   virtual bool is_active() const;
 
 public:
-  virtual bool begin_frame(FrameMode mode);
-  virtual void end_frame(FrameMode mode);
+  virtual bool begin_frame(FrameMode mode, Thread *current_thread);
+  virtual void end_frame(FrameMode mode, Thread *current_thread);
   virtual GraphicsOutput *get_host();
   
 private:

+ 2 - 1
panda/src/display/standardMunger.cxx

@@ -169,7 +169,8 @@ munge_data_impl(const GeomVertexData *data) {
 //  Description: Converts a Geom and/or its data as necessary.
 ////////////////////////////////////////////////////////////////////
 bool StandardMunger::
-munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data) {
+munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data,
+                Thread *current_thread) {
   int supported_geom_rendering = _gsg->get_supported_geom_rendering();
 
   int unsupported_bits = geom->get_geom_rendering() & ~supported_geom_rendering;

+ 2 - 1
panda/src/display/standardMunger.h

@@ -46,7 +46,8 @@ public:
 protected:
   virtual CPT(GeomVertexData) munge_data_impl(const GeomVertexData *data);
   virtual int compare_to_impl(const GeomMunger *other) const;
-  virtual bool munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &data);
+  virtual bool munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &data,
+                               Thread *current_thread);
   virtual int geom_compare_to_impl(const GeomMunger *other) const;
   virtual CPT(RenderState) munge_state_impl(const RenderState *state);
 

+ 6 - 4
panda/src/distort/projectionScreen.cxx

@@ -519,6 +519,8 @@ recompute_geom(Geom *geom, const LMatrix4f &rel_mat) {
      0.0f, 0.0f, 0.5f, 0.0f, 
      0.5f, 0.5f, 0.5f, 1.0f);
 
+  Thread *current_thread = Thread::get_current_thread();
+
   Lens *lens = _projector_node->get_lens();
   nassertv(lens != (Lens *)NULL);
 
@@ -546,11 +548,11 @@ recompute_geom(Geom *geom, const LMatrix4f &rel_mat) {
   PT(GeomVertexData) modify_vdata = geom->modify_vertex_data();
 
   // Maybe the vdata has animation that we should consider.
-  CPT(GeomVertexData) animated_vdata = geom->get_vertex_data()->animate_vertices();
+  CPT(GeomVertexData) animated_vdata = geom->get_vertex_data(current_thread)->animate_vertices(current_thread);
 
-  GeomVertexWriter texcoord(modify_vdata, _texcoord_name);
-  GeomVertexWriter color(modify_vdata);
-  GeomVertexReader vertex(animated_vdata, InternalName::get_vertex());
+  GeomVertexWriter texcoord(modify_vdata, _texcoord_name, current_thread);
+  GeomVertexWriter color(modify_vdata, current_thread);
+  GeomVertexReader vertex(animated_vdata, InternalName::get_vertex(), current_thread);
   
   if (_vignette_on) {
     color.set_column(InternalName::get_color());

+ 4 - 4
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -672,8 +672,8 @@ prepare_lens() {
 //               be called).
 ////////////////////////////////////////////////////////////////////
 bool DXGraphicsStateGuardian8::
-begin_frame() {
-  return GraphicsStateGuardian::begin_frame();
+begin_frame(Thread *current_thread) {
+  return GraphicsStateGuardian::begin_frame(current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -759,7 +759,7 @@ end_scene() {
 //               rendering the frame, and before the window flips.
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian8::
-end_frame() {
+end_frame(Thread *current_thread) {
 
 #if defined(DO_PSTATS)
   if (_texmgrmem_total_pcollector.is_active()) {
@@ -777,7 +777,7 @@ end_frame() {
   // Note: regular GraphicsWindow::end_frame is being called,
   // but we override gsg::end_frame, so need to explicitly call it here
   // (currently it's an empty fn)
-  GraphicsStateGuardian::end_frame();
+  GraphicsStateGuardian::end_frame(current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 2
panda/src/dxgsg8/dxGraphicsStateGuardian8.h

@@ -71,8 +71,8 @@ public:
   virtual CPT(TransformState) calc_projection_mat(const Lens *lens);
   virtual bool prepare_lens();
 
-  virtual bool begin_frame();
-  virtual bool begin_scene();
+  virtual bool begin_frame(Thread *current_thread, Thread *current_thread);
+  virtual bool begin_scene(Thread *current_thread, Thread *current_thread);
   virtual void end_scene();
   virtual void end_frame();
 

+ 4 - 4
panda/src/dxgsg8/wdxGraphicsBuffer8.cxx

@@ -83,7 +83,7 @@ wdxGraphicsBuffer8::
 //               should be skipped.
 ////////////////////////////////////////////////////////////////////
 bool wdxGraphicsBuffer8::
-begin_frame(FrameMode mode) {
+begin_frame(FrameMode mode, Thread *current_thread) {
 
   begin_frame_spam();
   if (_gsg == (GraphicsStateGuardian *)NULL) {
@@ -96,7 +96,7 @@ begin_frame(FrameMode mode) {
   }
   
   _gsg->set_current_properties(&get_fb_properties());
-  return _gsg->begin_frame();
+  return _gsg->begin_frame(current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -107,7 +107,7 @@ begin_frame(FrameMode mode) {
 //               should do whatever finalization is required.
 ////////////////////////////////////////////////////////////////////
 void wdxGraphicsBuffer8::
-end_frame(FrameMode mode) {
+end_frame(FrameMode mode, Thread *current_thread) {
 
   end_frame_spam();
   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
@@ -117,7 +117,7 @@ end_frame(FrameMode mode) {
     copy_to_textures();
   }
 
-  _gsg->end_frame();
+  _gsg->end_frame(current_thread);
 
   if (mode == FM_render) {
     trigger_flip();

+ 2 - 2
panda/src/dxgsg8/wdxGraphicsBuffer8.h

@@ -44,8 +44,8 @@ public:
                      GraphicsOutput *host);
   virtual ~wdxGraphicsBuffer8();
 
-  virtual bool begin_frame(FrameMode mode);
-  virtual void end_frame(FrameMode mode);
+  virtual bool begin_frame(FrameMode mode, Thread *current_thread);
+  virtual void end_frame(FrameMode mode, Thread *current_thread);
   
   virtual void select_cube_map(int cube_map_index);
 

+ 2 - 2
panda/src/dxgsg8/wdxGraphicsWindow8.cxx

@@ -76,7 +76,7 @@ wdxGraphicsWindow8::
 //               should be skipped.
 ////////////////////////////////////////////////////////////////////
 bool wdxGraphicsWindow8::
-begin_frame(FrameMode mode) {
+begin_frame(FrameMode mode, Thread *current_thread) {
   begin_frame_spam();
   if (_gsg == (GraphicsStateGuardian *)NULL) {
     return false;
@@ -100,7 +100,7 @@ begin_frame(FrameMode mode) {
   }
 
   _gsg->set_current_properties(&get_fb_properties());
-  bool return_val = _gsg->begin_frame();
+  bool return_val = _gsg->begin_frame(current_thread);
   _dxgsg->set_render_target();
   return return_val;
 }

+ 4 - 4
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -893,11 +893,11 @@ prepare_lens() {
 //               be called).
 ////////////////////////////////////////////////////////////////////
 bool DXGraphicsStateGuardian9::
-begin_frame() {
+begin_frame(Thread *current_thread) {
 
 DBG_S dxgsg9_cat.debug ( ) << "^^^^^^^^^^^ begin_frame \n"; DBG_E
 
-  GraphicsStateGuardian::begin_frame();
+  GraphicsStateGuardian::begin_frame(current_thread);
 
   if (_lru)
   {
@@ -1020,7 +1020,7 @@ DBG_S dxgsg9_cat.debug ( ) << "DXGraphicsStateGuardian9::end_scene\n"; DBG_E
 //               rendering the frame, and before the window flips.
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian9::
-end_frame() {
+end_frame(Thread *current_thread) {
 
 DBG_S dxgsg9_cat.debug ( ) << "@@@@@@@@@@ end_frame \n"; DBG_E
 
@@ -1133,7 +1133,7 @@ DBG_S dxgsg9_cat.debug ( ) << "@@@@@@@@@@ end_frame \n"; DBG_E
   // Note: regular GraphicsWindow::end_frame is being called,
   // but we override gsg::end_frame, so need to explicitly call it here
   // (currently it's an empty fn)
-  GraphicsStateGuardian::end_frame();
+  GraphicsStateGuardian::end_frame(current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 2
panda/src/dxgsg9/dxGraphicsStateGuardian9.h

@@ -107,8 +107,8 @@ public:
   virtual CPT(TransformState) calc_projection_mat(const Lens *lens);
   virtual bool prepare_lens();
 
-  virtual bool begin_frame();
-  virtual bool begin_scene();
+  virtual bool begin_frame(Thread *current_thread, Thread *current_thread);
+  virtual bool begin_scene(Thread *current_thread, Thread *current_thread);
   virtual void end_scene();
   virtual void end_frame();
 

+ 4 - 4
panda/src/dxgsg9/wdxGraphicsBuffer9.cxx

@@ -80,7 +80,7 @@ wdxGraphicsBuffer9::
 //               should be skipped.
 ////////////////////////////////////////////////////////////////////
 bool wdxGraphicsBuffer9::
-begin_frame(FrameMode mode) {
+begin_frame(FrameMode mode, Thread *current_thread) {
   DBG_S dxgsg9_cat.debug ( ) << "wdxGraphicsBuffer9::begin_frame\n"; DBG_E
 
   begin_frame_spam();
@@ -94,7 +94,7 @@ begin_frame(FrameMode mode) {
   }
   
   _gsg->set_current_properties(&get_fb_properties());
-  return _gsg->begin_frame();
+  return _gsg->begin_frame(current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -105,7 +105,7 @@ begin_frame(FrameMode mode) {
 //               should do whatever finalization is required.
 ////////////////////////////////////////////////////////////////////
 void wdxGraphicsBuffer9::
-end_frame(FrameMode mode) {
+end_frame(FrameMode mode, Thread *current_thread) {
 
   end_frame_spam();
   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
@@ -115,7 +115,7 @@ end_frame(FrameMode mode) {
     copy_to_textures();
   }
 
-  _gsg->end_frame();
+  _gsg->end_frame(current_thread);
 
   if (mode == FM_render) {
     trigger_flip();

+ 2 - 2
panda/src/dxgsg9/wdxGraphicsBuffer9.h

@@ -44,8 +44,8 @@ public:
                      GraphicsOutput *host);
   virtual ~wdxGraphicsBuffer9();
 
-  virtual bool begin_frame(FrameMode mode);
-  virtual void end_frame(FrameMode mode);
+  virtual bool begin_frame(FrameMode mode, Thread *current_thread);
+  virtual void end_frame(FrameMode mode, Thread *current_thread);
 
   virtual void select_cube_map(int cube_map_index);
   virtual void process_events();

+ 4 - 4
panda/src/dxgsg9/wdxGraphicsWindow9.cxx

@@ -96,7 +96,7 @@ make_current() {
 //               should be skipped.
 ////////////////////////////////////////////////////////////////////
 bool wdxGraphicsWindow9::
-begin_frame(FrameMode mode) {
+begin_frame(FrameMode mode, Thread *current_thread) {
   begin_frame_spam();
   if (_gsg == (GraphicsStateGuardian *)NULL) {
     return false;
@@ -120,7 +120,7 @@ begin_frame(FrameMode mode) {
   }
   
   _gsg->set_current_properties(&get_fb_properties());
-  bool return_val = _gsg->begin_frame();
+  bool return_val = _gsg->begin_frame(current_thread);
   _dxgsg->set_render_target();
   return return_val;
 }
@@ -133,7 +133,7 @@ begin_frame(FrameMode mode) {
 //               should do whatever finalization is required.
 ////////////////////////////////////////////////////////////////////
 void wdxGraphicsWindow9::
-end_frame(FrameMode mode) {
+end_frame(FrameMode mode, Thread *current_thread) {
 
   end_frame_spam();
   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
@@ -142,7 +142,7 @@ end_frame(FrameMode mode) {
     copy_to_textures();
   }
 
-  _gsg->end_frame();
+  _gsg->end_frame(current_thread);
 
   if (mode == FM_render) {
     trigger_flip();

+ 4 - 3
panda/src/framework/pandaFramework.cxx

@@ -744,9 +744,9 @@ enable_default_keys() {
 //               called only from main_loop().
 ////////////////////////////////////////////////////////////////////
 bool PandaFramework::
-do_frame() {
+do_frame(Thread *current_thread) {
   nassertr(_is_open, false);
-  DataGraphTraverser dg_trav;
+  DataGraphTraverser dg_trav(current_thread);
   dg_trav.traverse(_data_root.node());
 
   throw_event("NewFrame");
@@ -783,7 +783,8 @@ do_frame() {
 ////////////////////////////////////////////////////////////////////
 void PandaFramework::
 main_loop() {
-  while (do_frame()) {
+  Thread *current_thread = Thread::get_current_thread();
+  while (do_frame(current_thread)) {
   }
 }
 

+ 1 - 1
panda/src/framework/pandaFramework.h

@@ -108,7 +108,7 @@ public:
 
   void enable_default_keys();
 
-  virtual bool do_frame();
+  virtual bool do_frame(Thread *current_thread);
   void main_loop();
 
   INLINE void set_exit_flag();

+ 4 - 4
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -66,12 +66,12 @@ CLP(GraphicsBuffer)::
 //               should be skipped.
 ////////////////////////////////////////////////////////////////////
 bool CLP(GraphicsBuffer)::
-begin_frame(FrameMode mode) {
+begin_frame(FrameMode mode, Thread *current_thread) {
   if (!_is_valid) {
     return false;
   }
 
-  if (!_host->begin_frame(FM_parasite)) {
+  if (!_host->begin_frame(FM_parasite, current_thread)) {
     return false;
   }
   
@@ -366,7 +366,7 @@ generate_mipmaps() {
 //               should do whatever finalization is required.
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsBuffer)::
-end_frame(FrameMode mode) {
+end_frame(FrameMode mode, Thread *current_thread) {
   end_frame_spam();
   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
 
@@ -383,7 +383,7 @@ end_frame(FrameMode mode) {
     generate_mipmaps();
   }
 
-  _host->end_frame(FM_parasite);
+  _host->end_frame(FM_parasite, current_thread);
 
   if (mode == FM_render) {
     trigger_flip();

+ 2 - 2
panda/src/glstuff/glGraphicsBuffer_src.h

@@ -64,8 +64,8 @@ public:
                       GraphicsOutput *host);
   virtual ~CLP(GraphicsBuffer)();
 
-  virtual bool begin_frame(FrameMode mode);
-  virtual void end_frame(FrameMode mode);
+  virtual bool begin_frame(FrameMode mode, Thread *current_thread);
+  virtual void end_frame(FrameMode mode, Thread *current_thread);
 
   virtual void select_cube_map(int cube_map_index);
 

+ 20 - 19
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -1253,8 +1253,8 @@ prepare_lens() {
 //               be called).
 ////////////////////////////////////////////////////////////////////
 bool CLP(GraphicsStateGuardian)::
-begin_frame() {
-  if (!GraphicsStateGuardian::begin_frame()) {
+begin_frame(Thread *current_thread) {
+  if (!GraphicsStateGuardian::begin_frame(current_thread)) {
     return false;
   }
 
@@ -1276,7 +1276,7 @@ begin_frame() {
 //               rendering the frame, and before the window flips.
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
-end_frame() {
+end_frame(Thread *current_thread) {
 #ifdef DO_PSTATS
   // Check for textures, etc., that are no longer resident.  These
   // calls might be measurably expensive, and they don't have any
@@ -1295,7 +1295,7 @@ end_frame() {
   }
 #endif
 
-  GraphicsStateGuardian::end_frame();
+  GraphicsStateGuardian::end_frame(current_thread);
 
   // Flush any PCollectors specific to this kind of GSG.
   _primitive_batches_display_list_pcollector.flush_level();
@@ -1867,7 +1867,7 @@ disable_standard_vertex_arrays()
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 draw_triangles(const GeomPrimitivePipelineReader *reader) {
-  PStatTimer timer(_draw_primitive_pcollector);
+  PStatTimer timer(_draw_primitive_pcollector, reader->get_current_thread());
 
 #ifndef NDEBUG
   if (GLCAT.is_spam()) {
@@ -1912,7 +1912,7 @@ draw_triangles(const GeomPrimitivePipelineReader *reader) {
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 draw_tristrips(const GeomPrimitivePipelineReader *reader) {
-  PStatTimer timer(_draw_primitive_pcollector);
+  PStatTimer timer(_draw_primitive_pcollector, reader->get_current_thread());
 
   report_my_gl_errors();
 
@@ -1996,7 +1996,7 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) {
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 draw_trifans(const GeomPrimitivePipelineReader *reader) {
-  PStatTimer timer(_draw_primitive_pcollector);
+  PStatTimer timer(_draw_primitive_pcollector, reader->get_current_thread());
 #ifndef NDEBUG
   if (GLCAT.is_spam()) {
     GLCAT.spam() << "draw_trifans: " << *(reader->get_object()) << "\n";
@@ -2053,7 +2053,7 @@ draw_trifans(const GeomPrimitivePipelineReader *reader) {
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 draw_lines(const GeomPrimitivePipelineReader *reader) {
-  PStatTimer timer(_draw_primitive_pcollector);
+  PStatTimer timer(_draw_primitive_pcollector, reader->get_current_thread());
 #ifndef NDEBUG
   if (GLCAT.is_spam()) {
     GLCAT.spam() << "draw_lines: " << *(reader->get_object()) << "\n";
@@ -2095,7 +2095,7 @@ draw_lines(const GeomPrimitivePipelineReader *reader) {
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 draw_linestrips(const GeomPrimitivePipelineReader *reader) {
-  PStatTimer timer(_draw_primitive_pcollector);
+  PStatTimer timer(_draw_primitive_pcollector, reader->get_current_thread());
 #ifndef NDEBUG
   if (GLCAT.is_spam()) {
     GLCAT.spam() << "draw_linestrips: " << *(reader->get_object()) << "\n";
@@ -2111,7 +2111,7 @@ draw_linestrips(const GeomPrimitivePipelineReader *reader) {
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 draw_points(const GeomPrimitivePipelineReader *reader) {
-  PStatTimer timer(_draw_primitive_pcollector);
+  PStatTimer timer(_draw_primitive_pcollector, reader->get_current_thread());
 #ifndef NDEBUG
   if (GLCAT.is_spam()) {
     GLCAT.spam() << "draw_points: " << *(reader->get_object()) << "\n";
@@ -2617,9 +2617,10 @@ prepare_vertex_buffer(GeomVertexArrayData *data) {
 //               rendering.
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
-apply_vertex_buffer(VertexBufferContext *vbc) {
+apply_vertex_buffer(VertexBufferContext *vbc,
+                    const GeomVertexArrayDataPipelineReader *reader) {
   nassertv(_supports_buffers);
-  nassertv(vbc->get_data()->get_modified() != UpdateSeq::initial());
+  nassertv(reader->get_modified() != UpdateSeq::initial());
 
   CLP(VertexBufferContext) *gvbc = DCAST(CLP(VertexBufferContext), vbc);
 
@@ -2634,8 +2635,8 @@ apply_vertex_buffer(VertexBufferContext *vbc) {
   }
 
   if (gvbc->was_modified()) {
-    PStatTimer timer(_load_vertex_buffer_pcollector);
-    int num_bytes = gvbc->get_data()->get_data_size_bytes();
+    PStatTimer timer(_load_vertex_buffer_pcollector, reader->get_current_thread());
+    int num_bytes = reader->get_data_size_bytes();
     if (GLCAT.is_spam()) {
       GLCAT.spam()
         << "copying " << num_bytes
@@ -2644,12 +2645,12 @@ apply_vertex_buffer(VertexBufferContext *vbc) {
     if (num_bytes != 0) {
       if (gvbc->changed_size() || gvbc->changed_usage_hint()) {
         _glBufferData(GL_ARRAY_BUFFER, num_bytes,
-                      gvbc->get_data()->get_data(),
-                      get_usage(gvbc->get_data()->get_usage_hint()));
+                      reader->get_data(),
+                      get_usage(reader->get_usage_hint()));
 
       } else {
         _glBufferSubData(GL_ARRAY_BUFFER, 0, num_bytes,
-                         gvbc->get_data()->get_data());
+                         reader->get_data());
       }
       _data_transferred_pcollector.add_level(num_bytes);
     }
@@ -2738,7 +2739,7 @@ setup_array_data(const GeomVertexArrayDataPipelineReader *array_reader) {
   // Prepare the buffer object and bind it.
   VertexBufferContext *vbc = ((GeomVertexArrayData *)array_reader->get_object())->prepare_now(get_prepared_objects(), this);
   nassertr(vbc != (VertexBufferContext *)NULL, array_reader->get_data());
-  apply_vertex_buffer(vbc);
+  apply_vertex_buffer(vbc, array_reader);
 
   // NULL is the OpenGL convention for the first byte of the buffer object.
   return NULL;
@@ -2803,7 +2804,7 @@ apply_index_buffer(IndexBufferContext *ibc,
   }
 
   if (gibc->was_modified()) {
-    PStatTimer timer(_load_index_buffer_pcollector);
+    PStatTimer timer(_load_index_buffer_pcollector, reader->get_current_thread());
     int num_bytes = reader->get_data_size_bytes();
     if (GLCAT.is_spam()) {
       GLCAT.spam()

+ 4 - 3
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -100,8 +100,8 @@ public:
   virtual CPT(TransformState) calc_projection_mat(const Lens *lens);
   virtual bool prepare_lens();
 
-  virtual bool begin_frame();
-  virtual void end_frame();
+  virtual bool begin_frame(Thread *current_thread);
+  virtual void end_frame(Thread *current_thread);
 
   virtual bool begin_draw_primitives(const GeomPipelineReader *geom_reader, 
                                      const GeomMunger *munger,
@@ -129,7 +129,8 @@ public:
   void record_deleted_display_list(GLuint index);
 
   virtual VertexBufferContext *prepare_vertex_buffer(GeomVertexArrayData *data);
-  void apply_vertex_buffer(VertexBufferContext *vbc);
+  void apply_vertex_buffer(VertexBufferContext *vbc,
+                           const GeomVertexArrayDataPipelineReader *reader);
   virtual void release_vertex_buffer(VertexBufferContext *vbc);
   const unsigned char *setup_array_data(const GeomVertexArrayDataPipelineReader *data);
 

+ 5 - 5
panda/src/glxdisplay/glxGraphicsBuffer.cxx

@@ -75,8 +75,8 @@ glxGraphicsBuffer::
 //               should be skipped.
 ////////////////////////////////////////////////////////////////////
 bool glxGraphicsBuffer::
-begin_frame(FrameMode mode) {
-  PStatTimer timer(_make_current_pcollector);
+begin_frame(FrameMode mode, Thread *current_thread) {
+  PStatTimer timer(_make_current_pcollector, current_thread);
 
   begin_frame_spam();
   if (_gsg == (GraphicsStateGuardian *)NULL) {
@@ -99,7 +99,7 @@ begin_frame(FrameMode mode) {
   }
   
   _gsg->set_current_properties(&get_fb_properties());
-  return _gsg->begin_frame();
+  return _gsg->begin_frame(current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -110,7 +110,7 @@ begin_frame(FrameMode mode) {
 //               should do whatever finalization is required.
 ////////////////////////////////////////////////////////////////////
 void glxGraphicsBuffer::
-end_frame(FrameMode mode) {
+end_frame(FrameMode mode, Thread *current_thread) {
   end_frame_spam();
   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
 
@@ -119,7 +119,7 @@ end_frame(FrameMode mode) {
     copy_to_textures();
   }
 
-  _gsg->end_frame();
+  _gsg->end_frame(current_thread);
 
   if (mode == FM_render) {
     trigger_flip();

+ 2 - 2
panda/src/glxdisplay/glxGraphicsBuffer.h

@@ -43,8 +43,8 @@ public:
                     GraphicsOutput *host);
   virtual ~glxGraphicsBuffer();
 
-  virtual bool begin_frame(FrameMode mode);
-  virtual void end_frame(FrameMode mode);
+  virtual bool begin_frame(FrameMode mode, Thread *current_thread);
+  virtual void end_frame(FrameMode mode, Thread *current_thread);
 
 protected:
   virtual void close_buffer();

+ 5 - 5
panda/src/glxdisplay/glxGraphicsWindow.cxx

@@ -116,8 +116,8 @@ move_pointer(int device, int x, int y) {
 //               should be skipped.
 ////////////////////////////////////////////////////////////////////
 bool glxGraphicsWindow::
-begin_frame(FrameMode mode) {
-  PStatTimer timer(_make_current_pcollector);
+begin_frame(FrameMode mode, Thread *current_thread) {
+  PStatTimer timer(_make_current_pcollector, current_thread);
 
   begin_frame_spam();
   if (_gsg == (GraphicsStateGuardian *)NULL) {
@@ -145,7 +145,7 @@ begin_frame(FrameMode mode) {
   }
   
   _gsg->set_current_properties(&get_fb_properties());
-  return _gsg->begin_frame();
+  return _gsg->begin_frame(current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -156,7 +156,7 @@ begin_frame(FrameMode mode) {
 //               should do whatever finalization is required.
 ////////////////////////////////////////////////////////////////////
 void glxGraphicsWindow::
-end_frame(FrameMode mode) {
+end_frame(FrameMode mode, Thread *current_thread) {
   end_frame_spam();
   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
 
@@ -165,7 +165,7 @@ end_frame(FrameMode mode) {
     copy_to_textures();
   }
 
-  _gsg->end_frame();
+  _gsg->end_frame(current_thread);
 
   if (mode == FM_render) {
     trigger_flip();

+ 2 - 2
panda/src/glxdisplay/glxGraphicsWindow.h

@@ -41,8 +41,8 @@ public:
   virtual ~glxGraphicsWindow();
 
   virtual bool move_pointer(int device, int x, int y);
-  virtual bool begin_frame(FrameMode mode);
-  virtual void end_frame(FrameMode mode);
+  virtual bool begin_frame(FrameMode mode, Thread *current_thread);
+  virtual void end_frame(FrameMode mode, Thread *current_thread);
   virtual void begin_flip();
 
   virtual void process_events();

+ 3 - 3
panda/src/gobj/bufferResidencyTracker.cxx

@@ -45,9 +45,9 @@ BufferResidencyTracker(const string &pgo_name, const string &type_name) :
 //               initializes the active/inactive status.
 ////////////////////////////////////////////////////////////////////
 void BufferResidencyTracker::
-begin_frame() {
+begin_frame(Thread *current_thread) {
 #ifdef DO_PSTATS
-  int this_frame = ClockObject::get_global_clock()->get_frame_count();
+  int this_frame = ClockObject::get_global_clock()->get_frame_count(current_thread);
   if (_active_frame != this_frame) {
     _active_frame = this_frame;
 
@@ -68,7 +68,7 @@ begin_frame() {
 //               updates the PStatCollectors appropriately.
 ////////////////////////////////////////////////////////////////////
 void BufferResidencyTracker::
-end_frame() {
+end_frame(Thread *current_thread) {
   _inactive_nonresident_collector.set_level(_chains[S_inactive_nonresident].get_total_size());
   _active_nonresident_collector.set_level(_chains[S_active_nonresident].get_total_size());
   _inactive_resident_collector.set_level(_chains[S_inactive_resident].get_total_size());

+ 2 - 2
panda/src/gobj/bufferResidencyTracker.h

@@ -41,8 +41,8 @@ class EXPCL_PANDA BufferResidencyTracker {
 public:
   BufferResidencyTracker(const string &pgo_name, const string &type_name);
 
-  void begin_frame();
-  void end_frame();
+  void begin_frame(Thread *current_thread);
+  void end_frame(Thread *current_thread);
 
   INLINE BufferContextChain &get_inactive_nonresident();
   INLINE BufferContextChain &get_active_nonresident();

+ 9 - 7
panda/src/gobj/geom.I

@@ -86,8 +86,8 @@ get_usage_hint() const {
 //               modify) the geom's underlying data.
 ////////////////////////////////////////////////////////////////////
 INLINE CPT(GeomVertexData) Geom::
-get_vertex_data() const {
-  CDReader cdata(_cycler);
+get_vertex_data(Thread *current_thread) const {
+  CDReader cdata(_cycler, current_thread);
   return cdata->_data;
 }
 
@@ -279,11 +279,11 @@ INLINE void Geom::
 calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
                   bool &found_any, 
                   const GeomVertexData *vertex_data,
-                  bool got_mat, const LMatrix4f &mat) const {
-  int pipeline_stage = Thread::get_current_pipeline_stage();
+                  bool got_mat, const LMatrix4f &mat,
+                  Thread *current_thread) const {
   do_calc_tight_bounds(min_point, max_point, found_any, 
                        vertex_data, got_mat, mat,
-                       pipeline_stage);
+                       current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -301,9 +301,11 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
 ////////////////////////////////////////////////////////////////////
 INLINE void Geom::
 calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
-                  bool &found_any) const {
+                  bool &found_any, Thread *current_thread) const {
   calc_tight_bounds(min_point, max_point, found_any,
-                    get_vertex_data(), false, LMatrix4f::ident_mat());
+                    get_vertex_data(current_thread), false, 
+                    LMatrix4f::ident_mat(),
+                    current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 11 - 11
panda/src/gobj/geom.cxx

@@ -715,15 +715,14 @@ check_valid(const GeomVertexData *vertex_data) const {
 //  Description: Returns the bounding volume for the Geom.
 ////////////////////////////////////////////////////////////////////
 CPT(BoundingVolume) Geom::
-get_bounds() const {
-  int pipeline_stage = Thread::get_current_pipeline_stage();
-  CDStageReader cdata(_cycler, pipeline_stage);
+get_bounds(Thread *current_thread) const {
+  CDReader cdata(_cycler, current_thread);
   if (cdata->_internal_bounds_stale) {
-    CDStageWriter cdataw(((Geom *)this)->_cycler, pipeline_stage, cdata);
+    CDWriter cdataw(((Geom *)this)->_cycler, cdata, false);
     if (cdataw->_user_bounds != (BoundingVolume *)NULL) {
       cdataw->_internal_bounds = cdataw->_user_bounds;
     } else {
-      cdataw->_internal_bounds = compute_internal_bounds(pipeline_stage);
+      cdataw->_internal_bounds = compute_internal_bounds(current_thread);
     }
     cdataw->_internal_bounds_stale = false;
     return cdataw->_internal_bounds;
@@ -966,7 +965,7 @@ get_next_modified() {
 //               This includes all of the vertices.
 ////////////////////////////////////////////////////////////////////
 PT(BoundingVolume) Geom::
-compute_internal_bounds(int pipeline_stage) const {
+compute_internal_bounds(Thread *current_thread) const {
   // First, get ourselves a fresh, empty bounding volume.
   PT(BoundingVolume) bound = new BoundingSphere;
   GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, bound);
@@ -975,8 +974,9 @@ compute_internal_bounds(int pipeline_stage) const {
   // calc_tight_bounds to determine our minmax first.
   LPoint3f points[2];
   bool found_any = false;
-  do_calc_tight_bounds(points[0], points[1], found_any, get_vertex_data(),
-		       false, LMatrix4f::ident_mat(), pipeline_stage);
+  do_calc_tight_bounds(points[0], points[1], found_any, 
+                       get_vertex_data(current_thread),
+		       false, LMatrix4f::ident_mat(), current_thread);
   if (found_any) {
     // Then we put the bounding volume around both of those points.
     // Technically, we should put it around the eight points at the
@@ -1002,15 +1002,15 @@ do_calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
 		     bool &found_any, 
 		     const GeomVertexData *vertex_data,
 		     bool got_mat, const LMatrix4f &mat,
-		     int pipeline_stage) const {
-  CDStageReader cdata(_cycler, pipeline_stage);
+		     Thread *current_thread) const {
+  CDReader cdata(_cycler, current_thread);
   
   Primitives::const_iterator pi;
   for (pi = cdata->_primitives.begin(); 
        pi != cdata->_primitives.end();
        ++pi) {
     (*pi)->calc_tight_bounds(min_point, max_point, found_any, vertex_data,
-                             got_mat, mat);
+                             got_mat, mat, current_thread);
   }
 }
 

+ 7 - 6
panda/src/gobj/geom.h

@@ -74,7 +74,7 @@ PUBLISHED:
   INLINE UsageHint get_usage_hint() const;
   void set_usage_hint(UsageHint usage_hint);
 
-  INLINE CPT(GeomVertexData) get_vertex_data() const;
+  INLINE CPT(GeomVertexData) get_vertex_data(Thread *current_thread = Thread::get_current_thread()) const;
   PT(GeomVertexData) modify_vertex_data();
   void set_vertex_data(const GeomVertexData *data);
   void offset_vertices(const GeomVertexData *data, int offset);
@@ -105,7 +105,7 @@ PUBLISHED:
   bool check_valid() const;
   bool check_valid(const GeomVertexData *vertex_data) const;
 
-  CPT(BoundingVolume) get_bounds() const;
+  CPT(BoundingVolume) get_bounds(Thread *current_thread = Thread::get_current_thread()) const;
   INLINE void mark_bounds_stale() const;
   INLINE void set_bounds(const BoundingVolume *volume);
   INLINE void clear_bounds();
@@ -132,9 +132,10 @@ public:
   INLINE void calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
 				bool &found_any, 
 				const GeomVertexData *vertex_data,
-				bool got_mat, const LMatrix4f &mat) const;
+				bool got_mat, const LMatrix4f &mat,
+                                Thread *current_thread) const;
   INLINE void calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
-                                bool &found_any) const;
+                                bool &found_any, Thread *current_thread) const;
 
   static UpdateSeq get_next_modified();
 
@@ -146,13 +147,13 @@ private:
   class CData;
 
   INLINE void mark_internal_bounds_stale(CData *cdata);
-  PT(BoundingVolume) compute_internal_bounds(int pipeline_stage) const;
+  PT(BoundingVolume) compute_internal_bounds(Thread *current_thread) const;
 
   void do_calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
 			    bool &found_any, 
 			    const GeomVertexData *vertex_data,
 			    bool got_mat, const LMatrix4f &mat,
-			    int pipeline_stage) const;
+			    Thread *current_thread) const;
 
   void clear_prepared(PreparedGraphicsObjects *prepared_objects);
   bool check_will_be_valid(const GeomVertexData *vertex_data) const;

+ 7 - 6
panda/src/gobj/geomMunger.cxx

@@ -103,7 +103,8 @@ remove_data(const GeomVertexData *data) {
 //               same; so this result may be cached.
 ////////////////////////////////////////////////////////////////////
 void GeomMunger::
-munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data) {
+munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data,
+           Thread *current_thread) {
   CPT(GeomVertexData) source_data = data;
 
   // Look up the munger in the geom's cache--maybe we've recently
@@ -123,7 +124,7 @@ munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data) {
     entry->refresh();
 
     // Now check that it's fresh.
-    Geom::CDCacheReader cdata(entry->_cycler);
+    Geom::CDCacheReader cdata(entry->_cycler, current_thread);
     nassertv(cdata->_source == geom);
     if (cdata->_geom_result != (Geom *)NULL &&
 	geom->get_modified() <= cdata->_geom_result->get_modified() &&
@@ -142,11 +143,11 @@ munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data) {
   }
 
   // Ok, invoke the munger.
-  PStatTimer timer(_munge_pcollector);
+  PStatTimer timer(_munge_pcollector, current_thread);
 
   CPT(Geom) orig_geom = geom;
   data = munge_data(data);
-  munge_geom_impl(geom, data);
+  munge_geom_impl(geom, data, current_thread);
 
   // Record the new result in the cache.
   if (entry == (Geom::CacheEntry *)NULL) {
@@ -162,7 +163,7 @@ munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data) {
   }
 
   // Finally, store the cached result on the entry.
-  Geom::CDCacheWriter cdata(entry->_cycler, true);
+  Geom::CDCacheWriter cdata(entry->_cycler, true, current_thread);
   cdata->_source = (Geom *)orig_geom.p();
   cdata->set_result(geom, data);
 }
@@ -239,7 +240,7 @@ munge_data_impl(const GeomVertexData *data) {
 //  Description: Converts a Geom and/or its data as necessary.
 ////////////////////////////////////////////////////////////////////
 bool GeomMunger::
-munge_geom_impl(CPT(Geom) &, CPT(GeomVertexData) &) {
+munge_geom_impl(CPT(Geom) &, CPT(GeomVertexData) &, Thread *) {
   // The default implementation does nothing (the work has already
   // been done in munge_format_impl() and munge_data_impl()).
   return true;

+ 4 - 2
panda/src/gobj/geomMunger.h

@@ -72,7 +72,8 @@ public:
   INLINE CPT(GeomVertexData) munge_data(const GeomVertexData *data) const;
   void remove_data(const GeomVertexData *data);
 
-  void munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data);
+  void munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data,
+                  Thread *current_thread);
 
 public:
   INLINE int compare_to(const GeomMunger &other) const;
@@ -85,7 +86,8 @@ protected:
   virtual CPT(GeomVertexFormat) munge_format_impl(const GeomVertexFormat *orig,
                                                     const GeomVertexAnimationSpec &animation);
   virtual CPT(GeomVertexData) munge_data_impl(const GeomVertexData *data);
-  virtual bool munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &data);
+  virtual bool munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &data,
+                               Thread *current_thread);
   virtual int compare_to_impl(const GeomMunger *other) const;
   virtual int geom_compare_to_impl(const GeomMunger *other) const;
 

+ 6 - 4
panda/src/gobj/geomPrimitive.cxx

@@ -1122,14 +1122,16 @@ void GeomPrimitive::
 calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
                   bool &found_any, 
                   const GeomVertexData *vertex_data,
-                  bool got_mat, const LMatrix4f &mat) const {
-  GeomVertexReader reader(vertex_data, InternalName::get_vertex());
+                  bool got_mat, const LMatrix4f &mat,
+                  Thread *current_thread) const {
+  GeomVertexReader reader(vertex_data, InternalName::get_vertex(),
+                          current_thread);
   if (!reader.has_column()) {
     // No vertex data.
     return;
   }
 
-  CDReader cdata(_cycler);
+  CDReader cdata(_cycler, current_thread);
 
   if (cdata->_vertices == (GeomVertexArrayData *)NULL) {
     // Nonindexed case.
@@ -1173,7 +1175,7 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
 
   } else {
     // Indexed case.
-    GeomVertexReader index(cdata->_vertices, 0);
+    GeomVertexReader index(cdata->_vertices, 0, current_thread);
 
     if (got_mat) {
       while (!index.is_at_end()) {

+ 2 - 1
panda/src/gobj/geomPrimitive.h

@@ -192,7 +192,8 @@ public:
   void calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
                          bool &found_any, 
                          const GeomVertexData *vertex_data,
-                         bool got_mat, const LMatrix4f &mat) const;
+                         bool got_mat, const LMatrix4f &mat,
+                         Thread *current_thread) const;
 
 protected:
   virtual CPT(GeomPrimitive) decompose_impl() const;

+ 2 - 3
panda/src/gobj/geomVertexData.cxx

@@ -883,8 +883,8 @@ set_color(const Colorf &color, int num_components,
 //               graphics backend to update vertex buffers optimally).
 ////////////////////////////////////////////////////////////////////
 CPT(GeomVertexData) GeomVertexData::
-animate_vertices() const {
-  CDReader cdata(_cycler);
+animate_vertices(Thread *current_thread) const {
+  CDReader cdata(_cycler, current_thread);
 
   if (cdata->_format->get_animation().get_animation_type() != AT_panda) {
     return this;
@@ -1717,7 +1717,6 @@ make_array_readers() {
   }
 
   _got_array_readers = true;
-  nassertv(get_array_reader(0)->get_data_size_bytes() == get_array(0)->get_data_size_bytes());
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/gobj/geomVertexData.h

@@ -139,7 +139,7 @@ PUBLISHED:
     set_color(const Colorf &color, int num_components,
               NumericType numeric_type, Contents contents) const;
 
-  CPT(GeomVertexData) animate_vertices() const;
+  CPT(GeomVertexData) animate_vertices(Thread *current_thread) const;
 
   PT(GeomVertexData) 
     replace_column(InternalName *name, int num_components,

+ 17 - 12
panda/src/gobj/geomVertexReader.I

@@ -26,9 +26,9 @@
 //               it.
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexReader::
-GeomVertexReader() :
+GeomVertexReader(Thread *current_thread) :
   _vertex_data(NULL),
-  _current_thread(Thread::get_current_thread())
+  _current_thread(current_thread)
 {
   initialize();
 }
@@ -40,9 +40,10 @@ GeomVertexReader() :
 //               the indicated data object.
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexReader::
-GeomVertexReader(const GeomVertexData *vertex_data) :
+GeomVertexReader(const GeomVertexData *vertex_data,
+                 Thread *current_thread) :
   _vertex_data(vertex_data),
-  _current_thread(Thread::get_current_thread())
+  _current_thread(current_thread)
 {
   initialize();
 }
@@ -55,9 +56,10 @@ GeomVertexReader(const GeomVertexData *vertex_data) :
 //               reader specifically to process the named data type.
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexReader::
-GeomVertexReader(const GeomVertexData *vertex_data, const string &name) :
+GeomVertexReader(const GeomVertexData *vertex_data, const string &name,
+                 Thread *current_thread) :
   _vertex_data(vertex_data),
-  _current_thread(Thread::get_current_thread())
+  _current_thread(current_thread)
 {
   initialize();
   set_column(name);
@@ -72,9 +74,10 @@ GeomVertexReader(const GeomVertexData *vertex_data, const string &name) :
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexReader::
 GeomVertexReader(const GeomVertexData *vertex_data, 
-                   const InternalName *name) :
+                 const InternalName *name,
+                 Thread *current_thread) :
   _vertex_data(vertex_data),
-  _current_thread(Thread::get_current_thread())
+  _current_thread(current_thread)
 {
   initialize();
   set_column(name);
@@ -87,9 +90,10 @@ GeomVertexReader(const GeomVertexData *vertex_data,
 //               the indicated array only.
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexReader::
-GeomVertexReader(const GeomVertexArrayData *array_data) :
+GeomVertexReader(const GeomVertexArrayData *array_data,
+                 Thread *current_thread) :
   _array_data(array_data),
-  _current_thread(Thread::get_current_thread())
+  _current_thread(current_thread)
 {
   initialize();
 }
@@ -101,9 +105,10 @@ GeomVertexReader(const GeomVertexArrayData *array_data) :
 //               the indicated array only.
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexReader::
-GeomVertexReader(const GeomVertexArrayData *array_data, int column) :
+GeomVertexReader(const GeomVertexArrayData *array_data, int column,
+                 Thread *current_thread) :
   _array_data(array_data),
-  _current_thread(Thread::get_current_thread())
+  _current_thread(current_thread)
 {
   initialize();
   set_column(column);

+ 11 - 6
panda/src/gobj/geomVertexReader.h

@@ -59,15 +59,20 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA GeomVertexReader : public GeomEnums {
 PUBLISHED:
-  INLINE GeomVertexReader();
-  INLINE GeomVertexReader(const GeomVertexData *vertex_data);
+  INLINE GeomVertexReader(Thread *current_thread = Thread::get_current_thread());
   INLINE GeomVertexReader(const GeomVertexData *vertex_data,
-                          const string &name);
+                          Thread *current_thread = Thread::get_current_thread());
   INLINE GeomVertexReader(const GeomVertexData *vertex_data,
-                          const InternalName *name);
-  INLINE GeomVertexReader(const GeomVertexArrayData *array_data);
+                          const string &name,
+                          Thread *current_thread = Thread::get_current_thread());
+  INLINE GeomVertexReader(const GeomVertexData *vertex_data,
+                          const InternalName *name,
+                          Thread *current_thread = Thread::get_current_thread());
+  INLINE GeomVertexReader(const GeomVertexArrayData *array_data,
+                          Thread *current_thread = Thread::get_current_thread());
   INLINE GeomVertexReader(const GeomVertexArrayData *array_data, 
-                          int column);
+                          int column,
+                          Thread *current_thread = Thread::get_current_thread());
 
 public:
   INLINE GeomVertexReader(const GeomVertexDataPipelineReader *data_reader,

+ 16 - 12
panda/src/gobj/geomVertexWriter.I

@@ -26,9 +26,9 @@
 //               it.
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexWriter::
-GeomVertexWriter() :
+GeomVertexWriter(Thread *current_thread) :
   _vertex_data(NULL),
-  _current_thread(Thread::get_current_thread())
+  _current_thread(current_thread)
 {
   initialize();
 }
@@ -40,9 +40,9 @@ GeomVertexWriter() :
 //               the indicated data object.
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexWriter::
-GeomVertexWriter(GeomVertexData *vertex_data) :
+GeomVertexWriter(GeomVertexData *vertex_data, Thread *current_thread) :
   _vertex_data(vertex_data),
-  _current_thread(Thread::get_current_thread())
+  _current_thread(current_thread)
 {
   initialize();
 }
@@ -55,9 +55,10 @@ GeomVertexWriter(GeomVertexData *vertex_data) :
 //               writer specifically to process the named data type.
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexWriter::
-GeomVertexWriter(GeomVertexData *vertex_data, const string &name) :
+GeomVertexWriter(GeomVertexData *vertex_data, const string &name,
+                 Thread *current_thread) :
   _vertex_data(vertex_data),
-  _current_thread(Thread::get_current_thread())
+  _current_thread(current_thread)
 {
   initialize();
   set_column(name);
@@ -71,9 +72,10 @@ GeomVertexWriter(GeomVertexData *vertex_data, const string &name) :
 //               writer specifically to process the named data type.
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexWriter::
-GeomVertexWriter(GeomVertexData *vertex_data, const InternalName *name) :
+GeomVertexWriter(GeomVertexData *vertex_data, const InternalName *name,
+                 Thread *current_thread) :
   _vertex_data(vertex_data),
-  _current_thread(Thread::get_current_thread())
+  _current_thread(current_thread)
 {
   initialize();
   set_column(name);
@@ -86,9 +88,10 @@ GeomVertexWriter(GeomVertexData *vertex_data, const InternalName *name) :
 //               the indicated array only.
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexWriter::
-GeomVertexWriter(GeomVertexArrayData *array_data) :
+GeomVertexWriter(GeomVertexArrayData *array_data,
+                 Thread *current_thread) :
   _array_data(array_data),
-  _current_thread(Thread::get_current_thread())
+  _current_thread(current_thread)
 {
   initialize();
 }
@@ -100,9 +103,10 @@ GeomVertexWriter(GeomVertexArrayData *array_data) :
 //               the indicated array only.
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexWriter::
-GeomVertexWriter(GeomVertexArrayData *array_data, int column) :
+GeomVertexWriter(GeomVertexArrayData *array_data, int column,
+                 Thread *current_thread) :
   _array_data(array_data),
-  _current_thread(Thread::get_current_thread())
+  _current_thread(current_thread)
 {
   initialize();
   set_column(column);

+ 11 - 6
panda/src/gobj/geomVertexWriter.h

@@ -72,15 +72,20 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA GeomVertexWriter : public GeomEnums {
 PUBLISHED:
-  INLINE GeomVertexWriter();
-  INLINE GeomVertexWriter(GeomVertexData *vertex_data);
+  INLINE GeomVertexWriter(Thread *current_thread = Thread::get_current_thread());
   INLINE GeomVertexWriter(GeomVertexData *vertex_data,
-                          const string &name);
+                          Thread *current_thread = Thread::get_current_thread());
   INLINE GeomVertexWriter(GeomVertexData *vertex_data,
-                          const InternalName *name);
-  INLINE GeomVertexWriter(GeomVertexArrayData *array_data);
+                          const string &name,
+                          Thread *current_thread = Thread::get_current_thread());
+  INLINE GeomVertexWriter(GeomVertexData *vertex_data,
+                          const InternalName *name,
+                          Thread *current_thread = Thread::get_current_thread());
+  INLINE GeomVertexWriter(GeomVertexArrayData *array_data,
+                          Thread *current_thread = Thread::get_current_thread());
   INLINE GeomVertexWriter(GeomVertexArrayData *array_data, 
-                          int column);
+                          int column,
+                          Thread *current_thread = Thread::get_current_thread());
 
 public:
   INLINE GeomVertexWriter(GeomVertexDataPipelineWriter *data_writer,

+ 10 - 10
panda/src/gobj/preparedGraphicsObjects.cxx

@@ -834,8 +834,8 @@ prepare_index_buffer_now(GeomPrimitive *data, GraphicsStateGuardianBase *gsg) {
 //               passed to prepare_texture are actually loaded.
 ////////////////////////////////////////////////////////////////////
 void PreparedGraphicsObjects::
-begin_frame(GraphicsStateGuardianBase *gsg) {
-  ReMutexHolder holder(_lock);
+begin_frame(GraphicsStateGuardianBase *gsg, Thread *current_thread) {
+  ReMutexHolder holder(_lock, current_thread);
 
   // First, release all the textures, geoms, and buffers awaiting
   // release.
@@ -890,9 +890,9 @@ begin_frame(GraphicsStateGuardianBase *gsg) {
   _released_index_buffers.clear();
 
   // Reset the residency trackers.
-  _texture_residency.begin_frame();
-  _vbuffer_residency.begin_frame();
-  _ibuffer_residency.begin_frame();
+  _texture_residency.begin_frame(current_thread);
+  _vbuffer_residency.begin_frame(current_thread);
+  _ibuffer_residency.begin_frame(current_thread);
 
   // Now prepare all the textures, geoms, and buffers awaiting
   // preparation.
@@ -955,12 +955,12 @@ begin_frame(GraphicsStateGuardianBase *gsg) {
 //               frame.
 ////////////////////////////////////////////////////////////////////
 void PreparedGraphicsObjects::
-end_frame() {
-  ReMutexHolder holder(_lock);
+end_frame(Thread *current_thread) {
+  ReMutexHolder holder(_lock, current_thread);
 
-  _texture_residency.end_frame();
-  _vbuffer_residency.end_frame();
-  _ibuffer_residency.end_frame();
+  _texture_residency.end_frame(current_thread);
+  _vbuffer_residency.end_frame(current_thread);
+  _ibuffer_residency.end_frame(current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 3 - 2
panda/src/gobj/preparedGraphicsObjects.h

@@ -106,8 +106,9 @@ public:
   prepare_index_buffer_now(GeomPrimitive *data,
                            GraphicsStateGuardianBase *gsg);
 
-  void begin_frame(GraphicsStateGuardianBase *gsg);
-  void end_frame();
+  void begin_frame(GraphicsStateGuardianBase *gsg,
+                   Thread *current_thread);
+  void end_frame(Thread *current_thread);
 
 private:
   static string init_name();

+ 6 - 5
panda/src/grutil/multitexReducer.cxx

@@ -883,6 +883,7 @@ void MultitexReducer::
 transfer_geom(GeomNode *geom_node, const InternalName *texcoord_name,
               const MultitexReducer::GeomList &geom_list,
               bool preserve_color) {
+  Thread *current_thread = Thread::get_current_thread();
   GeomList::const_iterator gi;
   for (gi = geom_list.begin(); gi != geom_list.end(); ++gi) {
     const GeomInfo &geom_info = (*gi);
@@ -893,7 +894,7 @@ transfer_geom(GeomNode *geom_node, const InternalName *texcoord_name,
     PT(Geom) geom = orig_geom->make_copy();
 
     // Ensure that any vertex animation has been applied.
-    geom->set_vertex_data(geom->get_vertex_data()->animate_vertices());
+    geom->set_vertex_data(geom->get_vertex_data(current_thread)->animate_vertices(current_thread));
 
     // Now get a modifiable pointer to the vertex data in the new
     // Geom.  This will actually perform a deep copy of the vertex
@@ -902,8 +903,8 @@ transfer_geom(GeomNode *geom_node, const InternalName *texcoord_name,
     vdata->set_usage_hint(Geom::UH_stream);
     
     if (vdata->has_column(_target_stage->get_texcoord_name())) {
-      GeomVertexWriter vertex(vdata, InternalName::get_vertex());
-      GeomVertexReader texcoord(vdata, _target_stage->get_texcoord_name());
+      GeomVertexWriter vertex(vdata, InternalName::get_vertex(), current_thread);
+      GeomVertexReader texcoord(vdata, _target_stage->get_texcoord_name(), current_thread);
       
       while (!texcoord.is_at_end()) {
         const LVecBase2f &tc = texcoord.get_data2f();
@@ -923,8 +924,8 @@ transfer_geom(GeomNode *geom_node, const InternalName *texcoord_name,
            column->get_numeric_type(), column->get_contents());
         geom->set_vertex_data(vdata);
         
-        GeomVertexReader from(vdata, texcoord_name);
-        GeomVertexWriter to(vdata, InternalName::get_texcoord());
+        GeomVertexReader from(vdata, texcoord_name, current_thread);
+        GeomVertexWriter to(vdata, InternalName::get_texcoord(), current_thread);
         while (!from.is_at_end()) {
           to.add_data2f(from.get_data2f());
         }

+ 10 - 7
panda/src/parametrics/ropeNode.cxx

@@ -233,9 +233,10 @@ write(ostream &out, int indent_level) const {
 ////////////////////////////////////////////////////////////////////
 void RopeNode::
 reset_bound(const NodePath &rel_to) {
-  int pipeline_stage = Thread::get_current_pipeline_stage();
-  do_recompute_bounds(rel_to, pipeline_stage);
-  mark_internal_bounds_stale();
+  Thread *current_thread = Thread::get_current_thread();
+  int pipeline_stage = current_thread->get_pipeline_stage();
+  do_recompute_bounds(rel_to, pipeline_stage, current_thread);
+  mark_internal_bounds_stale(current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -247,8 +248,9 @@ reset_bound(const NodePath &rel_to) {
 //               thing.
 ////////////////////////////////////////////////////////////////////
 PT(BoundingVolume) RopeNode::
-compute_internal_bounds(int pipeline_stage) const {
-  return do_recompute_bounds(NodePath((PandaNode *)this), pipeline_stage);
+compute_internal_bounds(int pipeline_stage, Thread *current_thread) const {
+  return do_recompute_bounds(NodePath((PandaNode *)this), pipeline_stage, 
+                             current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -289,13 +291,14 @@ get_format(bool support_normals) const {
 //  Description: Does the actual internal recompute.
 ////////////////////////////////////////////////////////////////////
 PT(BoundingVolume) RopeNode::
-do_recompute_bounds(const NodePath &rel_to, int pipeline_stage) const {
+do_recompute_bounds(const NodePath &rel_to, int pipeline_stage, 
+                    Thread *current_thread) const {
   // TODO: fix the bounds so that it properly reflects the indicated
   // pipeline stage.  At the moment, we cheat and get some of the
   // properties from the current pipeline stage, the lazy way.
 
   // First, get ourselves a fresh, empty bounding volume.
-  PT(BoundingVolume) bound = PandaNode::compute_internal_bounds(pipeline_stage);
+  PT(BoundingVolume) bound = PandaNode::compute_internal_bounds(pipeline_stage, current_thread);
   nassertr(bound != (BoundingVolume *)NULL, bound);
   
   NurbsCurveEvaluator *curve = get_curve();

+ 3 - 2
panda/src/parametrics/ropeNode.h

@@ -142,13 +142,14 @@ PUBLISHED:
   void reset_bound(const NodePath &rel_to);
 
 protected:
-  virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage) const;
+  virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage, Thread *current_thread) const;
 
 private:
   CPT(GeomVertexFormat) get_format(bool support_normals) const;
 
   PT(BoundingVolume) do_recompute_bounds(const NodePath &rel_to,
-					 int pipeline_stage) const;
+					 int pipeline_stage, 
+                                         Thread *current_thread) const;
   void render_thread(CullTraverser *trav, CullTraverserData &data, 
                      NurbsCurveResult *result) const;
   void render_tape(CullTraverser *trav, CullTraverserData &data, 

+ 10 - 7
panda/src/parametrics/sheetNode.cxx

@@ -215,9 +215,10 @@ write(ostream &out, int indent_level) const {
 ////////////////////////////////////////////////////////////////////
 void SheetNode::
 reset_bound(const NodePath &rel_to) {
-  int pipeline_stage = Thread::get_current_pipeline_stage();
-  do_recompute_bounds(rel_to, pipeline_stage);
-  mark_internal_bounds_stale();
+  Thread *current_thread = Thread::get_current_thread();
+  int pipeline_stage = current_thread->get_pipeline_stage();
+  do_recompute_bounds(rel_to, pipeline_stage, current_thread);
+  mark_internal_bounds_stale(current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -229,8 +230,9 @@ reset_bound(const NodePath &rel_to) {
 //               thing.
 ////////////////////////////////////////////////////////////////////
 PT(BoundingVolume) SheetNode::
-compute_internal_bounds(int pipeline_stage) const {
-  return do_recompute_bounds(NodePath((PandaNode *)this), pipeline_stage);
+compute_internal_bounds(int pipeline_stage, Thread *current_thread) const {
+  return do_recompute_bounds(NodePath((PandaNode *)this), pipeline_stage,
+                             current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -239,13 +241,14 @@ compute_internal_bounds(int pipeline_stage) const {
 //  Description: Does the actual internal recompute.
 ////////////////////////////////////////////////////////////////////
 PT(BoundingVolume) SheetNode::
-do_recompute_bounds(const NodePath &rel_to, int pipeline_stage) const {
+do_recompute_bounds(const NodePath &rel_to, int pipeline_stage, 
+                    Thread *current_thread) const {
   // TODO: fix the bounds so that it properly reflects the indicated
   // pipeline stage.  At the moment, we cheat and get some of the
   // properties from the current pipeline stage, the lazy way.
 
   // First, get ourselves a fresh, empty bounding volume.
-  PT(BoundingVolume) bound = PandaNode::compute_internal_bounds(pipeline_stage);
+  PT(BoundingVolume) bound = PandaNode::compute_internal_bounds(pipeline_stage, current_thread);
   nassertr(bound != (BoundingVolume *)NULL, bound);
   
   NurbsSurfaceEvaluator *surface = get_surface();

+ 3 - 2
panda/src/parametrics/sheetNode.h

@@ -68,11 +68,12 @@ PUBLISHED:
   void reset_bound(const NodePath &rel_to);
 
 protected:
-  virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage) const;
+  virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage, Thread *current_thread) const;
 
 private:
   PT(BoundingVolume) do_recompute_bounds(const NodePath &rel_to,
-					 int pipeline_stage) const;
+					 int pipeline_stage,
+                                         Thread *current_thread) const;
   void render_sheet(CullTraverser *trav, CullTraverserData &data, 
                     NurbsSurfaceResult *result);
 

+ 1 - 11
panda/src/pgraph/cullBin.cxx

@@ -51,16 +51,6 @@ make_next() const {
   return (CullBin *)NULL;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: CullBin::add_object
-//       Access: Public, Virtual
-//  Description: Adds a geom, along with its associated state, to
-//               the bin for rendering.
-////////////////////////////////////////////////////////////////////
-void CullBin::
-add_object(CullableObject *) {
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: CullBin::finish_cull
 //       Access: Public, Virtual
@@ -71,7 +61,7 @@ add_object(CullableObject *) {
 //               draw.
 ////////////////////////////////////////////////////////////////////
 void CullBin::
-finish_cull(SceneSetup *) {
+finish_cull(SceneSetup *, Thread *) {
 }
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 2
panda/src/pgraph/cullBin.h

@@ -54,8 +54,8 @@ public:
 
   virtual PT(CullBin) make_next() const;
 
-  virtual void add_object(CullableObject *object)=0;
-  virtual void finish_cull(SceneSetup *scene_setup);
+  virtual void add_object(CullableObject *object, Thread *current_thread)=0;
+  virtual void finish_cull(SceneSetup *scene_setup, Thread *current_thread);
 
   virtual void draw(Thread *current_thread)=0;
 

+ 6 - 5
panda/src/pgraph/cullResult.cxx

@@ -98,6 +98,8 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
   static const Colorf flash_multisample_color(0.78f, 0.05f, 0.81f, 1.0f);
   static const Colorf flash_dual_color(0.92f, 0.01f, 0.01f, 1.0f);
 
+  Thread *current_thread = traverser->get_current_thread();
+
   // Check to see if there's a special transparency setting.
   const RenderState *state = object->_state;
   nassertv(state != (const RenderState *)NULL);
@@ -172,7 +174,7 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
 #ifndef NDEBUG
               check_flash_bin(transparent_part->_state, bin);
 #endif
-              bin->add_object(transparent_part);
+              bin->add_object(transparent_part, current_thread);
             }
           
           // Now we can draw the opaque part, with decals.  This will
@@ -206,8 +208,7 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
   // Munge vertices as needed for the GSG's requirements, and the
   // object's current state.
   object->munge_geom(_gsg, _gsg->get_geom_munger(object->_state), traverser);
-  
-  bin->add_object(object);
+  bin->add_object(object, current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -220,7 +221,7 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
 //               draw.
 ////////////////////////////////////////////////////////////////////
 void CullResult::
-finish_cull(SceneSetup *scene_setup) {
+finish_cull(SceneSetup *scene_setup, Thread *current_thread) {
   CullBinManager *bin_manager = CullBinManager::get_global_ptr();
 
   for (size_t i = 0; i < _bins.size(); ++i) {
@@ -232,7 +233,7 @@ finish_cull(SceneSetup *scene_setup) {
     } else {
       CullBin *bin = _bins[i];
       if (bin != (CullBin *)NULL) {
-        bin->finish_cull(scene_setup);
+        bin->finish_cull(scene_setup, current_thread);
       }
     }
   }

+ 1 - 1
panda/src/pgraph/cullResult.h

@@ -59,7 +59,7 @@ public:
   INLINE CullBin *get_bin(int bin_index);
 
   void add_object(CullableObject *object, const CullTraverser *traverser);
-  void finish_cull(SceneSetup *scene_setup);
+  void finish_cull(SceneSetup *scene_setup, Thread *current_thread);
   void draw(Thread *current_thread);
 
 public:

+ 11 - 0
panda/src/pgraph/cullTraverser.I

@@ -27,6 +27,17 @@ get_gsg() const {
   return _gsg;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CullTraverser::get_current_thread
+//       Access: Public
+//  Description: Returns the currently-executing thread object, as
+//               passed to the CullTraverser constructor.
+////////////////////////////////////////////////////////////////////
+INLINE Thread *CullTraverser::
+get_current_thread() const {
+  return _current_thread;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CullTraverser::set_scene
 //       Access: Public

+ 9 - 6
panda/src/pgraph/cullTraverser.cxx

@@ -50,8 +50,9 @@ TypeHandle CullTraverser::_type_handle;
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 CullTraverser::
-CullTraverser(GraphicsStateGuardianBase *gsg) :
-  _gsg(gsg)
+CullTraverser(GraphicsStateGuardianBase *gsg, Thread *current_thread) :
+  _gsg(gsg),
+  _current_thread(current_thread)
 {
   _camera_mask = DrawMask::all_on();
   _has_tag_state_key = false;
@@ -151,7 +152,7 @@ traverse(CullTraverserData &data) {
   // optimization, we should tag nodes with these properties as
   // being "fancy", and skip this processing for non-fancy nodes.
   
-  if (data.is_in_view(_camera_mask)) {
+  if (data.is_in_view(_camera_mask, _current_thread)) {
     if (pgraph_cat.is_spam()) {
       pgraph_cat.spam() 
         << "\n" << data._node_path
@@ -378,12 +379,14 @@ make_tight_bounds_viz(PandaNode *node) {
 
   LPoint3f n, x;
   bool found_any = false;
-  node->calc_tight_bounds(n, x, found_any, TransformState::make_identity());
+  node->calc_tight_bounds(n, x, found_any, TransformState::make_identity(),
+                          _current_thread);
   if (found_any) {
     PT(GeomVertexData) vdata = new GeomVertexData
       ("bounds", GeomVertexFormat::get_v3(),
       Geom::UH_stream);
-    GeomVertexWriter vertex(vdata, InternalName::get_vertex());
+    GeomVertexWriter vertex(vdata, InternalName::get_vertex(),
+                            _current_thread);
     
     vertex.add_data3f(n[0], n[1], n[2]);
     vertex.add_data3f(n[0], n[1], x[2]);
@@ -586,7 +589,7 @@ start_decal(const CullTraverserData &data) {
 ////////////////////////////////////////////////////////////////////
 CullableObject *CullTraverser::
 r_get_decals(CullTraverserData &data, CullableObject *decals) {
-  if (data.is_in_view(_camera_mask)) {
+  if (data.is_in_view(_camera_mask, _current_thread)) {
     PandaNode *node = data.node();
 
     const RenderEffects *node_effects = node->get_effects();

+ 3 - 1
panda/src/pgraph/cullTraverser.h

@@ -50,10 +50,11 @@ class NodePath;
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA CullTraverser : public TypedObject {
 public:
-  CullTraverser(GraphicsStateGuardianBase *gsg);
+  CullTraverser(GraphicsStateGuardianBase *gsg, Thread *current_thread);
   CullTraverser(const CullTraverser &copy);
 
   INLINE GraphicsStateGuardianBase *get_gsg() const;
+  INLINE Thread *get_current_thread() const;
 
   INLINE void set_scene(SceneSetup *scene_setup);
   INLINE SceneSetup *get_scene() const;
@@ -111,6 +112,7 @@ private:
                                CullableObject *decals);
 
   GraphicsStateGuardianBase *_gsg;
+  Thread *_current_thread;
   PT(SceneSetup) _scene_setup;
   DrawMask _camera_mask;
   bool _has_tag_state_key;

+ 3 - 3
panda/src/pgraph/cullTraverserData.I

@@ -128,13 +128,13 @@ get_net_transform(const CullTraverser *) const {
 //               work for future nodes.
 ////////////////////////////////////////////////////////////////////
 INLINE bool CullTraverserData::
-is_in_view(const DrawMask &camera_mask) {
-  if (node()->get_transform()->is_invalid()) {
+is_in_view(const DrawMask &camera_mask, Thread *current_thread) {
+  if (node()->get_transform(current_thread)->is_invalid()) {
     // If the transform is invalid, forget it.
     return false;
   }
 
-  if (!node()->compare_draw_mask(_draw_mask, camera_mask)) {
+  if (!node()->compare_draw_mask(_draw_mask, camera_mask, current_thread)) {
     // If there are no draw bits in common with the camera, the node
     // is out.
     return false;

+ 1 - 1
panda/src/pgraph/cullTraverserData.h

@@ -63,7 +63,7 @@ public:
   CPT(TransformState) get_modelview_transform(const CullTraverser *trav) const;
   INLINE const TransformState *get_net_transform(const CullTraverser *trav) const;
 
-  INLINE bool is_in_view(const DrawMask &camera_mask);
+  INLINE bool is_in_view(const DrawMask &camera_mask, Thread *current_thread);
   INLINE bool is_this_node_hidden(const CullTraverser *trav) const;
 
   void apply_transform_and_state(CullTraverser *trav);

+ 48 - 24
panda/src/pgraph/cullableObject.cxx

@@ -50,11 +50,21 @@ void CullableObject::
 munge_geom(GraphicsStateGuardianBase *gsg,
            GeomMunger *munger, const CullTraverser *traverser) {
   if (_geom != (Geom *)NULL) {
+    Thread *current_thread = traverser->get_current_thread();
     _munger = munger;
-    _munged_data = _geom->get_vertex_data();
-    nassertv(_geom->check_valid(_munged_data));
 
-    int geom_rendering = _geom->get_geom_rendering();
+    GeomPipelineReader geom_reader(_geom, current_thread);
+    _munged_data = geom_reader.get_vertex_data();
+
+#ifndef NDEBUG
+    {
+      GeomVertexDataPipelineReader data_reader(_munged_data, current_thread);
+      data_reader.check_array_readers();
+      nassertv(geom_reader.check_valid(&data_reader));
+    }
+#endif  // NDEBUG
+
+    int geom_rendering = geom_reader.get_geom_rendering();
     geom_rendering = _state->get_geom_rendering(geom_rendering);
     geom_rendering = _modelview_transform->get_geom_rendering(geom_rendering);
     
@@ -89,7 +99,7 @@ munge_geom(GraphicsStateGuardianBase *gsg,
       // the vertices in the CPU--and we have to do it before we call
       // munge_geom(), which might lose the tangent and binormal.
       CPT(GeomVertexData) animated_vertices = 
-        _munged_data->animate_vertices();
+        _munged_data->animate_vertices(current_thread);
       if (animated_vertices != _munged_data) {
         cpu_animated = true;
         _munged_data = animated_vertices;
@@ -99,7 +109,7 @@ munge_geom(GraphicsStateGuardianBase *gsg,
 
     // Now invoke the munger to ensure the resulting geometry is in
     // a GSG-friendly form.
-    munger->munge_geom(_geom, _munged_data);
+    munger->munge_geom(_geom, _munged_data, current_thread);
     
     StateMunger *state_munger;
     DCAST_INTO_V(state_munger, munger);
@@ -111,7 +121,7 @@ munge_geom(GraphicsStateGuardianBase *gsg,
       // animation in hardware--then we have to calculate that
       // animation now.
       CPT(GeomVertexData) animated_vertices = 
-        _munged_data->animate_vertices();
+        _munged_data->animate_vertices(current_thread);
       if (animated_vertices != _munged_data) {
         cpu_animated = true;
         _munged_data = animated_vertices;
@@ -120,7 +130,8 @@ munge_geom(GraphicsStateGuardianBase *gsg,
 
 #ifndef NDEBUG
     if (show_vertex_animation) {
-      bool hardware_animated = (_munged_data->get_format()->get_animation().get_animation_type() == Geom::AT_hardware);
+      GeomVertexDataPipelineReader data_reader(_munged_data, current_thread);
+      bool hardware_animated = (data_reader.get_format()->get_animation().get_animation_type() == Geom::AT_hardware);
       if (cpu_animated || hardware_animated) {
         // These vertices were animated, so flash them red or blue.
         static const double flash_rate = 1.0;  // 1 state change per second
@@ -178,17 +189,25 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 void CullableObject::
 munge_points_to_quads(const CullTraverser *traverser) {
-  PStatTimer timer(_munge_points_pcollector);
+  Thread *current_thread = traverser->get_current_thread();
+  PStatTimer timer(_munge_points_pcollector, current_thread);
 
   GraphicsStateGuardianBase *gsg = traverser->get_gsg();
 
-  GeomVertexReader vertex(_munged_data, InternalName::get_vertex());
-  GeomVertexReader normal(_munged_data, InternalName::get_normal());
-  GeomVertexReader color(_munged_data, InternalName::get_color());
-  GeomVertexReader texcoord(_munged_data, InternalName::get_texcoord());
-  GeomVertexReader rotate(_munged_data, InternalName::get_rotate());
-  GeomVertexReader size(_munged_data, InternalName::get_size());
-  GeomVertexReader aspect_ratio(_munged_data, InternalName::get_aspect_ratio());
+  GeomVertexReader vertex(_munged_data, InternalName::get_vertex(),
+                          current_thread);
+  GeomVertexReader normal(_munged_data, InternalName::get_normal(),
+                          current_thread);
+  GeomVertexReader color(_munged_data, InternalName::get_color(),
+                         current_thread);
+  GeomVertexReader texcoord(_munged_data, InternalName::get_texcoord(),
+                            current_thread);
+  GeomVertexReader rotate(_munged_data, InternalName::get_rotate(),
+                          current_thread);
+  GeomVertexReader size(_munged_data, InternalName::get_size(),
+                        current_thread);
+  GeomVertexReader aspect_ratio(_munged_data, InternalName::get_aspect_ratio(),
+                                current_thread);
 
   bool has_normal = (normal.has_column());
   bool has_color = (color.has_column());
@@ -301,9 +320,11 @@ munge_points_to_quads(const CullTraverser *traverser) {
   // CullFaceAttrib but will always render all of the vertices of the
   // polygons.  This is certainly a bug, but in order to fix it we'd
   // have to do the face culling ourselves--not sure if it's worth it.
-  int num_primitives = _geom->get_num_primitives();
+
+  GeomPipelineReader geom_reader(_geom, current_thread);
+  int num_primitives = geom_reader.get_num_primitives();
   for (int pi = 0; pi < num_primitives; ++pi) {
-    const GeomPrimitive *primitive = _geom->get_primitive(pi);
+    const GeomPrimitive *primitive = geom_reader.get_primitive(pi);
     if (primitive->get_num_vertices() != 0) {
       // We must first convert all of the points to eye space.
       int num_points = primitive->get_max_vertex() + 1;
@@ -314,7 +335,7 @@ munge_points_to_quads(const CullTraverser *traverser) {
       unsigned int *vertices_end = vertices + num_vertices;
 
       if (primitive->is_indexed()) {
-        GeomVertexReader index(primitive->get_vertices(), 0);
+        GeomVertexReader index(primitive->get_vertices(), 0, current_thread);
         for (unsigned int *vi = vertices; vi != vertices_end; ++vi) {
           // Get the point in eye-space coordinates.
           unsigned int v = index.get_data1i();
@@ -475,7 +496,8 @@ munge_points_to_quads(const CullTraverser *traverser) {
 ////////////////////////////////////////////////////////////////////
 void CullableObject::
 munge_texcoord_light_vector(const CullTraverser *traverser) {
-  PStatTimer timer(_munge_light_vector_pcollector);
+  Thread *current_thread = traverser->get_current_thread();
+  PStatTimer timer(_munge_light_vector_pcollector, current_thread);
 
   if (_net_transform->is_singular()) {
     // If we're under a singular transform, never mind.
@@ -547,11 +569,13 @@ munge_texcoord_light_vector(const CullTraverser *traverser) {
           _net_transform->invert_compose(light.get_net_transform());
         const LMatrix4f &light_mat = light_transform->get_mat();
 
-        GeomVertexWriter texcoord(new_data, texcoord_name);
-        GeomVertexReader vertex(new_data, InternalName::get_vertex());
-        GeomVertexReader tangent(new_data, tangent_name);
-        GeomVertexReader binormal(new_data, binormal_name);
-        GeomVertexReader normal(new_data, InternalName::get_normal());
+        GeomVertexWriter texcoord(new_data, texcoord_name, current_thread);
+        GeomVertexReader vertex(new_data, InternalName::get_vertex(),
+                                current_thread);
+        GeomVertexReader tangent(new_data, tangent_name, current_thread);
+        GeomVertexReader binormal(new_data, binormal_name, current_thread);
+        GeomVertexReader normal(new_data, InternalName::get_normal(),
+                                current_thread);
 
         while (!vertex.is_at_end()) {
           LPoint3f p = vertex.get_data3f();

+ 14 - 10
panda/src/pgraph/geomNode.cxx

@@ -349,17 +349,21 @@ combine_with(PandaNode *other) {
 ////////////////////////////////////////////////////////////////////
 CPT(TransformState) GeomNode::
 calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any,
-                  const TransformState *transform) const {
+                  const TransformState *transform, Thread *current_thread) const {
   CPT(TransformState) next_transform = 
-    PandaNode::calc_tight_bounds(min_point, max_point, found_any, transform);
+    PandaNode::calc_tight_bounds(min_point, max_point, found_any, transform,
+                                 current_thread);
 
   const LMatrix4f &mat = next_transform->get_mat();
-  int num_geoms = get_num_geoms();
-  for (int i = 0; i < num_geoms; i++) {
-    const Geom *geom = get_geom(i);
+
+  CDReader cdata(_cycler, current_thread);
+  Geoms::const_iterator gi;
+  for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
+    const Geom *geom = (*gi)._geom;
     geom->calc_tight_bounds(min_point, max_point, found_any,
-			    geom->get_vertex_data()->animate_vertices(),
-			    !next_transform->is_identity(), mat);
+			    geom->get_vertex_data(current_thread)->animate_vertices(current_thread),
+			    !next_transform->is_identity(), mat,
+                            current_thread);
   }
 
   return next_transform;
@@ -661,16 +665,16 @@ is_geom_node() const {
 //               something internally.
 ////////////////////////////////////////////////////////////////////
 PT(BoundingVolume) GeomNode::
-compute_internal_bounds(int pipeline_stage) const {
+compute_internal_bounds(int pipeline_stage, Thread *current_thread) const {
   // First, get ourselves a fresh, empty bounding volume.
-  PT(BoundingVolume) bound = PandaNode::compute_internal_bounds(pipeline_stage);
+  PT(BoundingVolume) bound = PandaNode::compute_internal_bounds(pipeline_stage, current_thread);
   nassertr(bound != (BoundingVolume *)NULL, bound);
 
   // Now actually compute the bounding volume by putting it around all
   // of our geoms' bounding volumes.
   pvector<const BoundingVolume *> child_volumes;
 
-  CDStageReader cdata(_cycler, pipeline_stage);
+  CDStageReader cdata(_cycler, pipeline_stage, current_thread);
   Geoms::const_iterator gi;
   for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
     const GeomEntry &entry = (*gi);

+ 3 - 2
panda/src/pgraph/geomNode.h

@@ -52,7 +52,8 @@ public:
   virtual CPT(TransformState)
     calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
                       bool &found_any,
-                      const TransformState *transform) const;
+                      const TransformState *transform,
+                      Thread *current_thread) const;
   virtual bool is_renderable() const;
   virtual CollideMask get_legal_collide_mask() const;
 
@@ -84,7 +85,7 @@ public:
   virtual bool is_geom_node() const;
 
 protected:
-  virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage) const;
+  virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage, Thread *current_thread) const;
 
 public:
   // This must be declared public so that VC6 will allow the nested

+ 58 - 55
panda/src/pgraph/nodePath.I

@@ -36,12 +36,12 @@ NodePath() :
 //               with the indicated name.
 ////////////////////////////////////////////////////////////////////
 INLINE NodePath::
-NodePath(const string &top_node_name) :
+NodePath(const string &top_node_name, Thread *current_thread) :
   _error_type(ET_ok)
 {
   PandaNode *top_node = new PandaNode(top_node_name);
-  int pipeline_stage = Thread::get_current_pipeline_stage();
-  _head = top_node->get_generic_component(false, pipeline_stage);
+  int pipeline_stage = current_thread->get_pipeline_stage();
+  _head = top_node->get_generic_component(false, pipeline_stage, current_thread);
   _backup_key = 0;
 }
 
@@ -57,12 +57,12 @@ NodePath(const string &top_node_name) :
 //               also NodePath::any_path(), below).
 ////////////////////////////////////////////////////////////////////
 INLINE NodePath::
-NodePath(PandaNode *node) :
+NodePath(PandaNode *node, Thread *current_thread) :
   _error_type(ET_ok)
 {
   if (node != (PandaNode *)NULL) {
-    int pipeline_stage = Thread::get_current_pipeline_stage();
-    _head = node->get_generic_component(false, pipeline_stage);
+    int pipeline_stage = current_thread->get_pipeline_stage();
+    _head = node->get_generic_component(false, pipeline_stage, current_thread);
   }
   _backup_key = 0;
 }
@@ -77,11 +77,12 @@ NodePath(PandaNode *node) :
 //               the path is ambiguous.
 ////////////////////////////////////////////////////////////////////
 INLINE NodePath NodePath::
-any_path(PandaNode *node) {
+any_path(PandaNode *node, Thread *current_thread) {
   NodePath result;
   if (node != (PandaNode *)NULL) {
-    int pipeline_stage = Thread::get_current_pipeline_stage();
-    result._head = node->get_generic_component(true, pipeline_stage);
+    int pipeline_stage = current_thread->get_pipeline_stage();
+    result._head = node->get_generic_component(true, pipeline_stage,
+                                               current_thread);
   }
   return result;
 }
@@ -94,13 +95,15 @@ any_path(PandaNode *node) {
 //               stashed or unstashed child of the parent.
 ////////////////////////////////////////////////////////////////////
 INLINE NodePath::
-NodePath(const NodePath &parent, PandaNode *child_node) :
+NodePath(const NodePath &parent, PandaNode *child_node, 
+         Thread *current_thread) :
   _error_type(ET_fail)
 {
   nassertv(!parent.is_empty());
   nassertv(child_node != (PandaNode *)NULL);
-  int pipeline_stage = Thread::get_current_pipeline_stage();
-  _head = PandaNode::get_component(parent._head, child_node, pipeline_stage);
+  int pipeline_stage = current_thread->get_pipeline_stage();
+  _head = PandaNode::get_component(parent._head, child_node, pipeline_stage,
+                                   current_thread);
   nassertv(_head != (NodePathComponent *)NULL);
 
   if (_head != (NodePathComponent *)NULL) {
@@ -229,9 +232,9 @@ is_empty() const {
 //               node.
 ////////////////////////////////////////////////////////////////////
 INLINE bool NodePath::
-is_singleton() const {
-  int pipeline_stage = Thread::get_current_pipeline_stage();
-  return (_head != (NodePathComponent *)NULL && _head->is_top_node(pipeline_stage));
+is_singleton(Thread *current_thread) const {
+  int pipeline_stage = current_thread->get_pipeline_stage();
+  return (_head != (NodePathComponent *)NULL && _head->is_top_node(pipeline_stage, current_thread));
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -252,12 +255,12 @@ get_error_type() const {
 //               is empty.  This requires iterating through the path.
 ////////////////////////////////////////////////////////////////////
 INLINE PandaNode *NodePath::
-get_top_node() const {
+get_top_node(Thread *current_thread) const {
   if (is_empty()) {
     return (PandaNode *)NULL;
   }
 
-  return get_top().node();
+  return get_top(current_thread).node();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -306,7 +309,7 @@ get_key() const {
 //               same (e.g., both "render").
 ////////////////////////////////////////////////////////////////////
 INLINE bool NodePath::
-is_same_graph(const NodePath &other) const {
+is_same_graph(const NodePath &other, Thread *current_thread) const {
   // Actually, it's possible for the top nodes to be the same, but the
   // NodePaths still to be considered in different graphs.  But even
   // in this case, get_top() will be different for each one.  (They'll
@@ -318,7 +321,7 @@ is_same_graph(const NodePath &other) const {
   // returns a different instance of render that appears to have the
   // same top node.  But this is a very rare thing to do.
   int a_count, b_count;
-  return (find_common_ancestor(*this, other, a_count, b_count) != (NodePathComponent *)NULL);
+  return (find_common_ancestor(*this, other, a_count, b_count, current_thread) != (NodePathComponent *)NULL);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -329,9 +332,9 @@ is_same_graph(const NodePath &other) const {
 //               or false if it is not.
 ////////////////////////////////////////////////////////////////////
 INLINE bool NodePath::
-is_ancestor_of(const NodePath &other) const {
+is_ancestor_of(const NodePath &other, Thread *current_thread) const {
   int a_count, b_count;
-  if (find_common_ancestor(*this, other, a_count, b_count) == (NodePathComponent *)NULL) {
+  if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) {
     // Not related.
     return false;
   }
@@ -350,9 +353,9 @@ is_ancestor_of(const NodePath &other) const {
 //               unrelated, returns NodePath::not_found().
 ////////////////////////////////////////////////////////////////////
 INLINE NodePath NodePath::
-get_common_ancestor(const NodePath &other) const {
+get_common_ancestor(const NodePath &other, Thread *current_thread) const {
   int a_count, b_count;
-  NodePathComponent *common = find_common_ancestor(*this, other, a_count, b_count);
+  NodePathComponent *common = find_common_ancestor(*this, other, a_count, b_count, current_thread);
   if (common == (NodePathComponent *)NULL) {
     return NodePath::not_found();
   }
@@ -368,9 +371,9 @@ get_common_ancestor(const NodePath &other) const {
 //  Description: Returns the number of children of the referenced node.
 ////////////////////////////////////////////////////////////////////
 INLINE int NodePath::
-get_num_children() const {
+get_num_children(Thread *current_thread) const {
   nassertr_always(!is_empty(), 0);
-  return _head->get_node()->get_num_children();
+  return _head->get_node()->get_num_children(current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -380,12 +383,12 @@ get_num_children() const {
 //               referenced node.
 ////////////////////////////////////////////////////////////////////
 INLINE NodePath NodePath::
-get_child(int n) const {
-  nassertr(n >= 0 && n < get_num_children(), NodePath());
+get_child(int n, Thread *current_thread) const {
+  nassertr(n >= 0 && n < get_num_children(current_thread), NodePath());
   NodePath child;
-  int pipeline_stage = Thread::get_current_pipeline_stage();
-  child._head = PandaNode::get_component(_head, _head->get_node()->get_child(n),
-					 pipeline_stage);
+  int pipeline_stage = current_thread->get_pipeline_stage();
+  child._head = PandaNode::get_component(_head, _head->get_node()->get_child(n, current_thread),
+					 pipeline_stage, current_thread);
   return child;
 }
 
@@ -396,8 +399,8 @@ get_child(int n) const {
 //               i.e. the NodePath chain contains at least two nodes.
 ////////////////////////////////////////////////////////////////////
 INLINE bool NodePath::
-has_parent() const {
-  return !is_empty() && !is_singleton();
+has_parent(Thread *current_thread) const {
+  return !is_empty() && !is_singleton(current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -409,15 +412,15 @@ has_parent() const {
 //               the empty NodePath.
 ////////////////////////////////////////////////////////////////////
 INLINE NodePath NodePath::
-get_parent() const {
-  if (!has_parent()) {
+get_parent(Thread *current_thread) const {
+  if (!has_parent(current_thread)) {
     return NodePath();
   }
 
-  int pipeline_stage = Thread::get_current_pipeline_stage();
+  int pipeline_stage = current_thread->get_pipeline_stage();
 
   NodePath parent;
-  parent._head = _head->get_next(pipeline_stage);
+  parent._head = _head->get_next(pipeline_stage, current_thread);
   return parent;
 }
 
@@ -429,10 +432,10 @@ get_parent() const {
 //               references it.
 ////////////////////////////////////////////////////////////////////
 INLINE NodePath NodePath::
-attach_new_node(const string &name, int sort) const {
-  nassertr(verify_complete(), NodePath::fail());
+attach_new_node(const string &name, int sort, Thread *current_thread) const {
+  nassertr(verify_complete(current_thread), NodePath::fail());
 
-  return attach_new_node(new PandaNode(name), sort);
+  return attach_new_node(new PandaNode(name), sort, current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -492,9 +495,9 @@ reverse_ls(ostream &out, int indent_level) const {
 //  Description: Changes the complete state object on this node.
 ////////////////////////////////////////////////////////////////////
 INLINE void NodePath::
-set_state(const RenderState *state) {
+set_state(const RenderState *state, Thread *current_thread) {
   nassertv_always(!is_empty());
-  node()->set_state(state);
+  node()->set_state(state, current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -503,9 +506,9 @@ set_state(const RenderState *state) {
 //  Description: Returns the net state on this node from the root.
 ////////////////////////////////////////////////////////////////////
 INLINE CPT(RenderState) NodePath::
-get_net_state() const {
+get_net_state(Thread *current_thread) const {
   nassertr(_error_type == ET_ok, RenderState::make_empty());
-  return r_get_net_state(_head);
+  return r_get_net_state(_head, current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -657,8 +660,8 @@ clear_effects() {
 //  Description: Sets the transform object on this node to identity.
 ////////////////////////////////////////////////////////////////////
 INLINE void NodePath::
-clear_transform() {
-  set_transform(TransformState::make_identity());
+clear_transform(Thread *current_thread) {
+  set_transform(TransformState::make_identity(), current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -667,9 +670,9 @@ clear_transform() {
 //  Description: Changes the complete transform object on this node.
 ////////////////////////////////////////////////////////////////////
 INLINE void NodePath::
-set_transform(const TransformState *transform) {
+set_transform(const TransformState *transform, Thread *current_thread) {
   nassertv_always(!is_empty());
-  node()->set_transform(transform);
+  node()->set_transform(transform, current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -680,8 +683,8 @@ set_transform(const TransformState *transform) {
 //               this node at the same position as the other node.
 ////////////////////////////////////////////////////////////////////
 INLINE void NodePath::
-clear_transform(const NodePath &other) {
-  set_transform(other, TransformState::make_identity());
+clear_transform(const NodePath &other, Thread *current_thread) {
+  set_transform(other, TransformState::make_identity(), current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -690,9 +693,9 @@ clear_transform(const NodePath &other) {
 //  Description: Returns the net transform on this node from the root.
 ////////////////////////////////////////////////////////////////////
 INLINE CPT(TransformState) NodePath::
-get_net_transform() const {
+get_net_transform(Thread *current_thread) const {
   nassertr(_error_type == ET_ok, TransformState::make_identity());
-  return r_get_net_transform(_head);
+  return r_get_net_transform(_head, current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -704,9 +707,9 @@ get_net_transform() const {
 //               calculations.
 ////////////////////////////////////////////////////////////////////
 INLINE void NodePath::
-set_prev_transform(const TransformState *transform) {
+set_prev_transform(const TransformState *transform, Thread *current_thread) {
   nassertv_always(!is_empty());
-  node()->set_prev_transform(transform);
+  node()->set_prev_transform(transform, current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -716,9 +719,9 @@ set_prev_transform(const TransformState *transform) {
 //               from the root.  See set_prev_transform().
 ////////////////////////////////////////////////////////////////////
 INLINE CPT(TransformState) NodePath::
-get_net_prev_transform() const {
+get_net_prev_transform(Thread *current_thread) const {
   nassertr(_error_type == ET_ok, TransformState::make_identity());
-  return r_get_net_prev_transform(_head);
+  return r_get_net_prev_transform(_head, current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 167 - 154
panda/src/pgraph/nodePath.cxx

@@ -77,12 +77,12 @@ TypeHandle NodePath::_type_handle;
 //  Description: Returns the number of nodes in the path.
 ////////////////////////////////////////////////////////////////////
 int NodePath::
-get_num_nodes() const {
+get_num_nodes(Thread *current_thread) const {
   if (is_empty()) {
     return 0;
   }
-  int pipeline_stage = Thread::get_current_pipeline_stage();
-  return _head->get_length(pipeline_stage);
+  int pipeline_stage = current_thread->get_pipeline_stage();
+  return _head->get_length(pipeline_stage, current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -99,17 +99,17 @@ get_num_nodes() const {
 //               NodePath, and is the one most frequently referenced).
 ////////////////////////////////////////////////////////////////////
 PandaNode *NodePath::
-get_node(int index) const {
+get_node(int index, Thread *current_thread) const {
   nassertr(index >= 0 && index < get_num_nodes(), NULL);
 
-  int pipeline_stage = Thread::get_current_pipeline_stage();
+  int pipeline_stage = current_thread->get_pipeline_stage();
 
   NodePathComponent *comp = _head;
   while (index > 0) {
     // If this assertion fails, the index was out of range; the
     // component's length must have been invalid.
     nassertr(comp != (NodePathComponent *)NULL, NULL);
-    comp = comp->get_next(pipeline_stage);
+    comp = comp->get_next(pipeline_stage, current_thread);
     index--;
   }
 
@@ -126,16 +126,16 @@ get_node(int index) const {
 //               of the path, or empty NodePath if this path is empty.
 ////////////////////////////////////////////////////////////////////
 NodePath NodePath::
-get_top() const {
+get_top(Thread *current_thread) const {
   if (is_empty()) {
     return *this;
   }
 
-  int pipeline_stage = Thread::get_current_pipeline_stage();
+  int pipeline_stage = current_thread->get_pipeline_stage();
 
   NodePathComponent *comp = _head;
-  while (!comp->is_top_node(pipeline_stage)) {
-    comp = comp->get_next(pipeline_stage);
+  while (!comp->is_top_node(pipeline_stage, current_thread)) {
+    comp = comp->get_next(pipeline_stage, current_thread);
     nassertr(comp != (NodePathComponent *)NULL, NULL);
   }
 
@@ -152,20 +152,20 @@ get_top() const {
 //               node.
 ////////////////////////////////////////////////////////////////////
 NodePathCollection NodePath::
-get_children() const {
+get_children(Thread *current_thread) const {
   NodePathCollection result;
   nassertr_always(!is_empty(), result);
 
   PandaNode *bottom_node = node();
 
-  int pipeline_stage = Thread::get_current_pipeline_stage();
+  int pipeline_stage = current_thread->get_pipeline_stage();
 
   PandaNode::Children cr = bottom_node->get_children();
   int num_children = cr.get_num_children();
   for (int i = 0; i < num_children; i++) {
     NodePath child;
     child._head = PandaNode::get_component(_head, cr.get_child(i),
-					   pipeline_stage);
+					   pipeline_stage, current_thread);
     result.add_path(child);
   }
 
@@ -181,19 +181,19 @@ get_children() const {
 //               the list returned by get_children().
 ////////////////////////////////////////////////////////////////////
 NodePathCollection NodePath::
-get_stashed_children() const {
+get_stashed_children(Thread *current_thread) const {
   NodePathCollection result;
   nassertr_always(!is_empty(), result);
 
   PandaNode *bottom_node = node();
 
-  int pipeline_stage = Thread::get_current_pipeline_stage();
+  int pipeline_stage = current_thread->get_pipeline_stage();
 
   int num_stashed = bottom_node->get_num_stashed();
   for (int i = 0; i < num_stashed; i++) {
     NodePath stashed;
     stashed._head = PandaNode::get_component(_head, bottom_node->get_stashed(i),
-					     pipeline_stage);
+					     pipeline_stage, current_thread);
     result.add_path(stashed);
   }
 
@@ -210,14 +210,14 @@ get_stashed_children() const {
 //               list of children.
 ////////////////////////////////////////////////////////////////////
 int NodePath::
-get_sort() const {
+get_sort(Thread *current_thread) const {
   if (!has_parent()) {
     return 0;
   }
 
-  int pipeline_stage = Thread::get_current_pipeline_stage();
+  int pipeline_stage = current_thread->get_pipeline_stage();
 
-  PandaNode *parent = _head->get_next(pipeline_stage)->get_node();
+  PandaNode *parent = _head->get_next(pipeline_stage, current_thread)->get_node();
   PandaNode *child = node();
   nassertr(parent != (PandaNode *)NULL && child != (PandaNode *)NULL, 0);
   int child_index = parent->find_child(child);
@@ -328,7 +328,7 @@ find_all_paths_to(PandaNode *node) const {
 //               same thing as detach_node().
 ////////////////////////////////////////////////////////////////////
 void NodePath::
-reparent_to(const NodePath &other, int sort) {
+reparent_to(const NodePath &other, int sort, Thread *current_thread) {
   nassertv(verify_complete());
   nassertv(other.verify_complete());
   nassertv_always(!is_empty());
@@ -337,9 +337,9 @@ reparent_to(const NodePath &other, int sort) {
   // Reparenting implicitly resets the delta vector.
   node()->reset_prev_transform();
 
-  int pipeline_stage = Thread::get_current_pipeline_stage();
+  int pipeline_stage = current_thread->get_pipeline_stage();
   bool reparented = PandaNode::reparent(other._head, _head, sort, false,
-					pipeline_stage);
+					pipeline_stage, current_thread);
   nassertv(reparented);
 }
 
@@ -353,21 +353,21 @@ reparent_to(const NodePath &other, int sort) {
 //               different coordinate system.
 ////////////////////////////////////////////////////////////////////
 void NodePath::
-wrt_reparent_to(const NodePath &other, int sort) {
-  nassertv(verify_complete());
-  nassertv(other.verify_complete());
+wrt_reparent_to(const NodePath &other, int sort, Thread *current_thread) {
+  nassertv(verify_complete(current_thread));
+  nassertv(other.verify_complete(current_thread));
   nassertv_always(!is_empty());
   nassertv(other._error_type == ET_ok);
 
-  if (get_transform() == get_prev_transform()) {
-    set_transform(get_transform(other));
-    node()->reset_prev_transform();
+  if (get_transform(current_thread) == get_prev_transform(current_thread)) {
+    set_transform(get_transform(other, current_thread), current_thread);
+    node()->reset_prev_transform(current_thread);
   } else {
-    set_transform(get_transform(other));
-    set_prev_transform(get_prev_transform(other));
+    set_transform(get_transform(other, current_thread), current_thread);
+    set_prev_transform(get_prev_transform(other, current_thread), current_thread);
   }
 
-  reparent_to(other, sort);
+  reparent_to(other, sort, current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -395,7 +395,7 @@ wrt_reparent_to(const NodePath &other, int sort) {
 //               return a different get_id() value.
 ////////////////////////////////////////////////////////////////////
 NodePath NodePath::
-instance_to(const NodePath &other, int sort) const {
+instance_to(const NodePath &other, int sort, Thread *current_thread) const {
   nassertr(verify_complete(), NodePath::fail());
   nassertr(other.verify_complete(), NodePath::fail());
   nassertr_always(!is_empty(), NodePath::fail());
@@ -405,12 +405,14 @@ instance_to(const NodePath &other, int sort) const {
 
   // First, we'll attach to NULL, to guarantee we get a brand new
   // instance.
-  int pipeline_stage = Thread::get_current_pipeline_stage();
-  new_instance._head = PandaNode::attach(NULL, node(), sort, pipeline_stage);
+  int pipeline_stage = current_thread->get_pipeline_stage();
+  new_instance._head = PandaNode::attach(NULL, node(), sort, pipeline_stage,
+                                         current_thread);
 
   // Now, we'll reparent the new instance to the target node.
   bool reparented = PandaNode::reparent(other._head, new_instance._head,
-                                        sort, false, pipeline_stage);
+                                        sort, false, pipeline_stage,
+                                        current_thread);
   nassertr(reparented, new_instance);
 
   // instance_to() doesn't reset the velocity delta, unlike most of
@@ -431,11 +433,12 @@ instance_to(const NodePath &other, int sort) const {
 //               this instance.
 ////////////////////////////////////////////////////////////////////
 NodePath NodePath::
-instance_under_node(const NodePath &other, const string &name, int sort) const {
-  NodePath new_node = other.attach_new_node(name, sort);
-  NodePath instance = instance_to(new_node);
+instance_under_node(const NodePath &other, const string &name, int sort,
+                    Thread *current_thread) const {
+  NodePath new_node = other.attach_new_node(name, sort, current_thread);
+  NodePath instance = instance_to(new_node, 0, current_thread);
   if (instance.is_empty()) {
-    new_node.remove_node();
+    new_node.remove_node(current_thread);
     return instance;
   }
   return new_node;
@@ -451,19 +454,19 @@ instance_under_node(const NodePath &other, const string &name, int sort) const {
 //               returned.
 ////////////////////////////////////////////////////////////////////
 NodePath NodePath::
-copy_to(const NodePath &other, int sort) const {
-  nassertr(verify_complete(), fail());
-  nassertr(other.verify_complete(), fail());
+copy_to(const NodePath &other, int sort, Thread *current_thread) const {
+  nassertr(verify_complete(current_thread), fail());
+  nassertr(other.verify_complete(current_thread), fail());
   nassertr_always(!is_empty(), fail());
   nassertr(other._error_type == ET_ok, fail());
 
   PandaNode *source_node = node();
-  PT(PandaNode) copy_node = source_node->copy_subgraph();
+  PT(PandaNode) copy_node = source_node->copy_subgraph(current_thread);
   nassertr(copy_node != (PandaNode *)NULL, fail());
 
-  copy_node->reset_prev_transform();
+  copy_node->reset_prev_transform(current_thread);
 
-  return other.attach_new_node(copy_node, sort);
+  return other.attach_new_node(copy_node, sort, current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -483,14 +486,15 @@ copy_to(const NodePath &other, int sort) const {
 //               returned.
 ////////////////////////////////////////////////////////////////////
 NodePath NodePath::
-attach_new_node(PandaNode *node, int sort) const {
-  nassertr(verify_complete(), NodePath::fail());
+attach_new_node(PandaNode *node, int sort, Thread *current_thread) const {
+  nassertr(verify_complete(current_thread), NodePath::fail());
   nassertr(_error_type == ET_ok, NodePath::fail());
   nassertr(node != (PandaNode *)NULL, NodePath::fail());
 
   NodePath new_path(*this);
-  int pipeline_stage = Thread::get_current_pipeline_stage();
-  new_path._head = PandaNode::attach(_head, node, sort, pipeline_stage);
+  int pipeline_stage = current_thread->get_pipeline_stage();
+  new_path._head = PandaNode::attach(_head, node, sort, pipeline_stage,
+                                     current_thread);
   return new_path;
 }
 
@@ -516,17 +520,17 @@ attach_new_node(PandaNode *node, int sort) const {
 //               as the NodePath exists.
 ////////////////////////////////////////////////////////////////////
 void NodePath::
-remove_node() {
+remove_node(Thread *current_thread) {
   nassertv(_error_type != ET_not_found);
 
   // If we have no parents, remove_node() is just a do-nothing
   // operation; if we have no nodes, maybe we were already removed.
   // In either case, quietly do nothing except to ensure the
   // NodePath is clear.
-  if (!is_empty() && !is_singleton()) {
-    node()->reset_prev_transform();
-    int pipeline_stage = Thread::get_current_pipeline_stage();
-    PandaNode::detach(_head, pipeline_stage);
+  if (!is_empty() && !is_singleton(current_thread)) {
+    node()->reset_prev_transform(current_thread);
+    int pipeline_stage = current_thread->get_pipeline_stage();
+    PandaNode::detach(_head, pipeline_stage, current_thread);
   }
 
   if (is_empty() || _head->has_key()) {
@@ -563,12 +567,12 @@ remove_node() {
 //               as the NodePath exists.
 ////////////////////////////////////////////////////////////////////
 void NodePath::
-detach_node() {
+detach_node(Thread *current_thread) {
   nassertv(_error_type != ET_not_found);
   if (!is_empty() && !is_singleton()) {
     node()->reset_prev_transform();
-    int pipeline_stage = Thread::get_current_pipeline_stage();
-    PandaNode::detach(_head, pipeline_stage);
+    int pipeline_stage = current_thread->get_pipeline_stage();
+    PandaNode::detach(_head, pipeline_stage, current_thread);
   }
 }
 
@@ -607,11 +611,11 @@ output(ostream &out) const {
 //  Description: Returns the complete state object set on this node.
 ////////////////////////////////////////////////////////////////////
 const RenderState *NodePath::
-get_state() const {
+get_state(Thread *current_thread) const {
   // This method is declared non-inline to avoid a compiler bug in
   // gcc-3.4 and gcc-4.0.
   nassertr_always(!is_empty(), RenderState::make_empty());
-  return node()->get_state();
+  return node()->get_state(current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -622,21 +626,21 @@ get_state() const {
 //               render state of the other node.
 ////////////////////////////////////////////////////////////////////
 CPT(RenderState) NodePath::
-get_state(const NodePath &other) const {
+get_state(const NodePath &other, Thread *current_thread) const {
   nassertr(_error_type == ET_ok && other._error_type == ET_ok, RenderState::make_empty());
 
   if (other.is_empty()) {
-    return get_net_state();
+    return get_net_state(current_thread);
   }
   if (is_empty()) {
-    return other.get_net_state()->invert_compose(RenderState::make_empty());
+    return other.get_net_state(current_thread)->invert_compose(RenderState::make_empty());
   }
     
-  nassertr(verify_complete(), RenderState::make_empty());
-  nassertr(other.verify_complete(), RenderState::make_empty());
+  nassertr(verify_complete(current_thread), RenderState::make_empty());
+  nassertr(other.verify_complete(current_thread), RenderState::make_empty());
 
   int a_count, b_count;
-  if (find_common_ancestor(*this, other, a_count, b_count) == (NodePathComponent *)NULL) {
+  if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) {
     if (allow_unrelated_wrt) {
       pgraph_cat.debug()
         << *this << " is not related to " << other << "\n";
@@ -647,8 +651,8 @@ get_state(const NodePath &other) const {
     }
   }
 
-  CPT(RenderState) a_state = r_get_partial_state(_head, a_count);
-  CPT(RenderState) b_state = r_get_partial_state(other._head, b_count);
+  CPT(RenderState) a_state = r_get_partial_state(_head, a_count, current_thread);
+  CPT(RenderState) b_state = r_get_partial_state(other._head, b_count, current_thread);
   return b_state->invert_compose(a_state);
 }
 
@@ -661,20 +665,21 @@ get_state(const NodePath &other) const {
 //               other node.
 ////////////////////////////////////////////////////////////////////
 void NodePath::
-set_state(const NodePath &other, const RenderState *state) {
+set_state(const NodePath &other, const RenderState *state,
+          Thread *current_thread) {
   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(RenderState) rel_state;
   if (has_parent()) {
-    rel_state = other.get_state(get_parent());
+    rel_state = other.get_state(get_parent(current_thread), current_thread);
   } else {
-    rel_state = other.get_state(NodePath());
+    rel_state = other.get_state(NodePath(), current_thread);
   }
 
   CPT(RenderState) new_state = rel_state->compose(state);
-  set_state(new_state);
+  set_state(new_state, current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -683,11 +688,11 @@ set_state(const NodePath &other, const RenderState *state) {
 //  Description: Returns the complete transform object set on this node.
 ////////////////////////////////////////////////////////////////////
 const TransformState *NodePath::
-get_transform() const {
+get_transform(Thread *current_thread) const {
   // This method is declared non-inline to avoid a compiler bug in
   // gcc-3.4 and gcc-4.0.
   nassertr_always(!is_empty(), TransformState::make_identity());
-  return node()->get_transform();
+  return node()->get_transform(current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -698,21 +703,21 @@ get_transform() const {
 //               as seen from the other node.
 ////////////////////////////////////////////////////////////////////
 CPT(TransformState) NodePath::
-get_transform(const NodePath &other) const {
+get_transform(const NodePath &other, Thread *current_thread) const {
   nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity());
 
   if (other.is_empty()) {
-    return get_net_transform();
+    return get_net_transform(current_thread);
   }
   if (is_empty()) {
-    return other.get_net_transform()->invert_compose(TransformState::make_identity());
+    return other.get_net_transform(current_thread)->invert_compose(TransformState::make_identity());
   }
     
-  nassertr(verify_complete(), TransformState::make_identity());
-  nassertr(other.verify_complete(), TransformState::make_identity());
+  nassertr(verify_complete(current_thread), TransformState::make_identity());
+  nassertr(other.verify_complete(current_thread), TransformState::make_identity());
 
   int a_count, b_count;
-  if (find_common_ancestor(*this, other, a_count, b_count) == (NodePathComponent *)NULL) {
+  if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) {
     if (allow_unrelated_wrt) {
       if (pgraph_cat.is_debug()) {
         pgraph_cat.debug()
@@ -727,16 +732,16 @@ get_transform(const NodePath &other) const {
 
   CPT(TransformState) a_transform, b_transform;
 
-  a_transform = r_get_partial_transform(_head, a_count);
+  a_transform = r_get_partial_transform(_head, a_count, current_thread);
   if (a_transform != (TransformState *)NULL) {
-    b_transform = r_get_partial_transform(other._head, b_count);
+    b_transform = r_get_partial_transform(other._head, b_count, current_thread);
   }
   if (b_transform == (TransformState *)NULL) {
     // If either path involved a node with a net_transform
     // RenderEffect applied, we have to go all the way up to the root
     // to get the right answer.
-    a_transform = r_get_net_transform(_head);
-    b_transform = r_get_net_transform(other._head);
+    a_transform = r_get_net_transform(_head, current_thread);
+    b_transform = r_get_net_transform(other._head, current_thread);
   }
   return b_transform->invert_compose(a_transform);
 }
@@ -750,20 +755,21 @@ get_transform(const NodePath &other) const {
 //               other node.
 ////////////////////////////////////////////////////////////////////
 void NodePath::
-set_transform(const NodePath &other, const TransformState *transform) {
+set_transform(const NodePath &other, const TransformState *transform,
+              Thread *current_thread) {
   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_transform(get_parent());
+    rel_trans = other.get_transform(get_parent(current_thread), current_thread);
   } else {
-    rel_trans = other.get_transform(NodePath());
+    rel_trans = other.get_transform(NodePath(), current_thread);
   }
 
   CPT(TransformState) new_trans = rel_trans->compose(transform);
-  set_transform(new_trans);
+  set_transform(new_trans, current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -774,11 +780,11 @@ set_transform(const NodePath &other, const TransformState *transform) {
 //               set_prev_transform().
 ////////////////////////////////////////////////////////////////////
 const TransformState *NodePath::
-get_prev_transform() const {
+get_prev_transform(Thread *current_thread) const {
   // This method is declared non-inline to avoid a compiler bug in
   // gcc-3.4 and gcc-4.0.
   nassertr_always(!is_empty(), TransformState::make_identity());
-  return node()->get_prev_transform();
+  return node()->get_prev_transform(current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -790,21 +796,21 @@ get_prev_transform() const {
 //               in the previous frame.
 ////////////////////////////////////////////////////////////////////
 CPT(TransformState) NodePath::
-get_prev_transform(const NodePath &other) const {
+get_prev_transform(const NodePath &other, Thread *current_thread) const {
   nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity());
 
   if (other.is_empty()) {
-    return get_net_prev_transform();
+    return get_net_prev_transform(current_thread);
   }
   if (is_empty()) {
-    return other.get_net_prev_transform()->invert_compose(TransformState::make_identity());
+    return other.get_net_prev_transform(current_thread)->invert_compose(TransformState::make_identity());
   }
     
-  nassertr(verify_complete(), TransformState::make_identity());
-  nassertr(other.verify_complete(), TransformState::make_identity());
+  nassertr(verify_complete(current_thread), TransformState::make_identity());
+  nassertr(other.verify_complete(current_thread), TransformState::make_identity());
 
   int a_count, b_count;
-  if (find_common_ancestor(*this, other, a_count, b_count) == (NodePathComponent *)NULL) {
+  if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) {
     if (allow_unrelated_wrt) {
       pgraph_cat.debug()
         << *this << " is not related to " << other << "\n";
@@ -815,8 +821,8 @@ get_prev_transform(const NodePath &other) const {
     }
   }
 
-  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);
+  CPT(TransformState) a_prev_transform = r_get_partial_prev_transform(_head, a_count, current_thread);
+  CPT(TransformState) b_prev_transform = r_get_partial_prev_transform(other._head, b_count, current_thread);
   return b_prev_transform->invert_compose(a_prev_transform);
 }
 
@@ -829,20 +835,21 @@ get_prev_transform(const NodePath &other) const {
 //               when seen from the other node.
 ////////////////////////////////////////////////////////////////////
 void NodePath::
-set_prev_transform(const NodePath &other, const TransformState *transform) {
+set_prev_transform(const NodePath &other, const TransformState *transform,
+                   Thread *current_thread) {
   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());
+  if (has_parent(current_thread)) {
+    rel_trans = other.get_prev_transform(get_parent(current_thread), current_thread);
   } else {
-    rel_trans = other.get_prev_transform(NodePath());
+    rel_trans = other.get_prev_transform(NodePath(), current_thread);
   }
 
   CPT(TransformState) new_trans = rel_trans->compose(transform);
-  set_prev_transform(new_trans);
+  set_prev_transform(new_trans, current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -5146,13 +5153,13 @@ get_antialias() const {
 //               is hidden (and the node should be visible).
 ////////////////////////////////////////////////////////////////////
 NodePath NodePath::
-get_hidden_ancestor(DrawMask camera_mask) const {
-  int pipeline_stage = Thread::get_current_pipeline_stage();
+get_hidden_ancestor(DrawMask camera_mask, Thread *current_thread) const {
+  int pipeline_stage = current_thread->get_pipeline_stage();
 
   NodePathComponent *comp;
   for (comp = _head; 
        comp != (NodePathComponent *)NULL; 
-       comp = comp->get_next(pipeline_stage)) {
+       comp = comp->get_next(pipeline_stage, current_thread)) {
     PandaNode *node = comp->get_node();
     if (node->is_overall_hidden() ||
         ((node->get_draw_show_mask() | ~node->get_draw_control_mask()) & camera_mask).is_zero()) {
@@ -5181,13 +5188,14 @@ get_hidden_ancestor(DrawMask camera_mask) const {
 //               retrieve it).
 ////////////////////////////////////////////////////////////////////
 void NodePath::
-stash(int sort) {
+stash(int sort, Thread *current_thread) {
   nassertv_always(!is_singleton() && !is_empty());
   nassertv(verify_complete());
 
-  int pipeline_stage = Thread::get_current_pipeline_stage();
-  bool reparented = PandaNode::reparent(_head->get_next(pipeline_stage),
-					_head, sort, true, pipeline_stage);
+  int pipeline_stage = current_thread->get_pipeline_stage();
+  bool reparented = PandaNode::reparent(_head->get_next(pipeline_stage, current_thread),
+					_head, sort, true, pipeline_stage,
+                                        current_thread);
   nassertv(reparented);
 }
 
@@ -5200,13 +5208,14 @@ stash(int sort) {
 //               scene graph.
 ////////////////////////////////////////////////////////////////////
 void NodePath::
-unstash(int sort) {
+unstash(int sort, Thread *current_thread) {
   nassertv_always(!is_singleton() && !is_empty());
   nassertv(verify_complete());
 
-  int pipeline_stage = Thread::get_current_pipeline_stage();
-  bool reparented = PandaNode::reparent(_head->get_next(pipeline_stage),
-					_head, sort, false, pipeline_stage);
+  int pipeline_stage = current_thread->get_pipeline_stage();
+  bool reparented = PandaNode::reparent(_head->get_next(pipeline_stage, current_thread),
+					_head, sort, false, pipeline_stage,
+                                        current_thread);
   nassertv(reparented);
 }
 
@@ -5216,10 +5225,10 @@ unstash(int sort) {
 //  Description: Unstashes this node and all stashed child nodes.
 ////////////////////////////////////////////////////////////////////
 void NodePath::
-unstash_all() {
+unstash_all(Thread *current_thread) {
   NodePathCollection stashed_descendents = find_all_matches("**/@@*");
   stashed_descendents.unstash();
-  unstash();
+  unstash(0, current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -5231,11 +5240,11 @@ unstash_all() {
 //               be visible).
 ////////////////////////////////////////////////////////////////////
 NodePath NodePath::
-get_stashed_ancestor() const {
+get_stashed_ancestor(Thread *current_thread) const {
   NodePathComponent *comp = _head;
   if (comp != (NodePathComponent *)NULL) {
-    int pipeline_stage = Thread::get_current_pipeline_stage();
-    NodePathComponent *next = comp->get_next(pipeline_stage);
+    int pipeline_stage = current_thread->get_pipeline_stage();
+    NodePathComponent *next = comp->get_next(pipeline_stage, current_thread);
 
     while (next != (NodePathComponent *)NULL) {
       PandaNode *node = comp->get_node();
@@ -5248,7 +5257,7 @@ get_stashed_ancestor() const {
       }
 
       comp = next;
-      next = next->get_next(pipeline_stage);
+      next = next->get_next(pipeline_stage, current_thread);
     }
   }
 
@@ -5262,7 +5271,7 @@ get_stashed_ancestor() const {
 //               NodePath are connected, or false otherwise.
 ////////////////////////////////////////////////////////////////////
 bool NodePath::
-verify_complete() const {
+verify_complete(Thread *current_thread) const {
   if (is_empty()) {
     return true;
   }
@@ -5270,13 +5279,13 @@ verify_complete() const {
   const NodePathComponent *comp = _head;
   nassertr(comp != (const NodePathComponent *)NULL, false);
 
-  int pipeline_stage = Thread::get_current_pipeline_stage();
+  int pipeline_stage = current_thread->get_pipeline_stage();
 
   PandaNode *node = comp->get_node();
   nassertr(node != (const PandaNode *)NULL, false);
-  int length = comp->get_length(pipeline_stage);
+  int length = comp->get_length(pipeline_stage, current_thread);
 
-  comp = comp->get_next(pipeline_stage);
+  comp = comp->get_next(pipeline_stage, current_thread);
   length--;
   while (comp != (const NodePathComponent *)NULL) {
     PandaNode *next_node = comp->get_node();
@@ -5289,16 +5298,16 @@ verify_complete() const {
       return false;
     }
 
-    if (comp->get_length(pipeline_stage) != length) {
+    if (comp->get_length(pipeline_stage, current_thread) != length) {
       pgraph_cat.warning()
         << *this << " is incomplete; length at " << *next_node
-        << " indicates " << comp->get_length(pipeline_stage)
+        << " indicates " << comp->get_length(pipeline_stage, current_thread)
 	<< " while length at " << *node << " indicates " << length << "\n";
       return false;
     }
 
     node = next_node;
-    comp = comp->get_next(pipeline_stage);
+    comp = comp->get_next(pipeline_stage, current_thread);
     length--;
   }
 
@@ -5434,14 +5443,16 @@ write_bounds(ostream &out) const {
 //               bounding volume, or false if none are.
 ////////////////////////////////////////////////////////////////////
 bool NodePath::
-calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point) {
+calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
+                  Thread *current_thread) {
   min_point.set(0.0f, 0.0f, 0.0f);
   max_point.set(0.0f, 0.0f, 0.0f);
   nassertr_always(!is_empty(), false);
 
   bool found_any = false;
   node()->calc_tight_bounds(min_point, max_point, found_any, 
-                            TransformState::make_identity());
+                            TransformState::make_identity(),
+                            current_thread);
 
   return found_any;
 }
@@ -5641,24 +5652,24 @@ write_bam_file(const string &filename) const {
 ////////////////////////////////////////////////////////////////////
 NodePathComponent *NodePath::
 find_common_ancestor(const NodePath &a, const NodePath &b,
-                     int &a_count, int &b_count) {
+                     int &a_count, int &b_count, Thread *current_thread) {
   nassertr(!a.is_empty() && !b.is_empty(), NULL);
   NodePathComponent *ac = a._head;
   NodePathComponent *bc = b._head;
   a_count = 0;
   b_count = 0;
 
-  int pipeline_stage = Thread::get_current_pipeline_stage();
+  int pipeline_stage = current_thread->get_pipeline_stage();
 
   // Shorten up the longer one until they are the same length.
-  while (ac->get_length(pipeline_stage) > bc->get_length(pipeline_stage)) {
+  while (ac->get_length(pipeline_stage, current_thread) > bc->get_length(pipeline_stage, current_thread)) {
     nassertr(ac != (NodePathComponent *)NULL, NULL);
-    ac = ac->get_next(pipeline_stage);
+    ac = ac->get_next(pipeline_stage, current_thread);
     a_count++;
   }
-  while (bc->get_length(pipeline_stage) > ac->get_length(pipeline_stage)) {
+  while (bc->get_length(pipeline_stage, current_thread) > ac->get_length(pipeline_stage, current_thread)) {
     nassertr(bc != (NodePathComponent *)NULL, NULL);
-    bc = bc->get_next(pipeline_stage);
+    bc = bc->get_next(pipeline_stage, current_thread);
     b_count++;
   }
 
@@ -5667,9 +5678,9 @@ find_common_ancestor(const NodePath &a, const NodePath &b,
     // These shouldn't go to NULL unless they both go there together. 
     nassertr(ac != (NodePathComponent *)NULL, NULL);
     nassertr(bc != (NodePathComponent *)NULL, NULL);
-    ac = ac->get_next(pipeline_stage);
+    ac = ac->get_next(pipeline_stage, current_thread);
     a_count++;
-    bc = bc->get_next(pipeline_stage);
+    bc = bc->get_next(pipeline_stage, current_thread);
     b_count++;
   }
 
@@ -5683,13 +5694,13 @@ find_common_ancestor(const NodePath &a, const NodePath &b,
 //               indicated component node from the root of the graph.
 ////////////////////////////////////////////////////////////////////
 CPT(RenderState) NodePath::
-r_get_net_state(NodePathComponent *comp) const {
+r_get_net_state(NodePathComponent *comp, Thread *current_thread) const {
   if (comp == (NodePathComponent *)NULL) {
     return RenderState::make_empty();
   } else {
     CPT(RenderState) state = comp->get_node()->get_state();
-    int pipeline_stage = Thread::get_current_pipeline_stage();
-    return r_get_net_state(comp->get_next(pipeline_stage))->compose(state);
+    int pipeline_stage = current_thread->get_pipeline_stage();
+    return r_get_net_state(comp->get_next(pipeline_stage, current_thread), current_thread)->compose(state);
   }
 }
 
@@ -5702,13 +5713,14 @@ r_get_net_state(NodePathComponent *comp) const {
 //               net transform from the root of the graph.
 ////////////////////////////////////////////////////////////////////
 CPT(RenderState) NodePath::
-r_get_partial_state(NodePathComponent *comp, int n) const {
+r_get_partial_state(NodePathComponent *comp, int n, 
+                    Thread *current_thread) const {
   if (n == 0 || comp == (NodePathComponent *)NULL) {
     return RenderState::make_empty();
   } else {
     CPT(RenderState) state = comp->get_node()->get_state();
-    int pipeline_stage = Thread::get_current_pipeline_stage();
-    return r_get_partial_state(comp->get_next(pipeline_stage), n - 1)->compose(state);
+    int pipeline_stage = current_thread->get_pipeline_stage();
+    return r_get_partial_state(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread)->compose(state);
   }
 }
 
@@ -5719,12 +5731,12 @@ r_get_partial_state(NodePathComponent *comp, int n) const {
 //               indicated component node from the root of the graph.
 ////////////////////////////////////////////////////////////////////
 CPT(TransformState) NodePath::
-r_get_net_transform(NodePathComponent *comp) const {
+r_get_net_transform(NodePathComponent *comp, Thread *current_thread) const {
   if (comp == (NodePathComponent *)NULL) {
     return TransformState::make_identity();
   } else {
-    int pipeline_stage = Thread::get_current_pipeline_stage();
-    CPT(TransformState) net_transform = r_get_net_transform(comp->get_next(pipeline_stage));
+    int pipeline_stage = current_thread->get_pipeline_stage();
+    CPT(TransformState) net_transform = r_get_net_transform(comp->get_next(pipeline_stage, current_thread), current_thread);
     CPT(TransformState) transform = comp->get_node()->get_transform();
 
     CPT(RenderEffects) effects = comp->get_node()->get_effects();
@@ -5749,7 +5761,8 @@ r_get_net_transform(NodePathComponent *comp) const {
 //               transform cannot be easily determined.
 ////////////////////////////////////////////////////////////////////
 CPT(TransformState) NodePath::
-r_get_partial_transform(NodePathComponent *comp, int n) const {
+r_get_partial_transform(NodePathComponent *comp, int n, 
+                        Thread *current_thread) const {
   if (n == 0 || comp == (NodePathComponent *)NULL) {
     return TransformState::make_identity();
   } else {
@@ -5757,8 +5770,8 @@ r_get_partial_transform(NodePathComponent *comp, int n) const {
       return NULL;
     }
     CPT(TransformState) transform = comp->get_node()->get_transform();
-    int pipeline_stage = Thread::get_current_pipeline_stage();
-    CPT(TransformState) partial = r_get_partial_transform(comp->get_next(pipeline_stage), n - 1);
+    int pipeline_stage = current_thread->get_pipeline_stage();
+    CPT(TransformState) partial = r_get_partial_transform(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread);
     if (partial == (const TransformState *)NULL) {
       return NULL;
     }
@@ -5774,13 +5787,13 @@ r_get_partial_transform(NodePathComponent *comp, int n) const {
 //               graph.
 ////////////////////////////////////////////////////////////////////
 CPT(TransformState) NodePath::
-r_get_net_prev_transform(NodePathComponent *comp) const {
+r_get_net_prev_transform(NodePathComponent *comp, Thread *current_thread) const {
   if (comp == (NodePathComponent *)NULL) {
     return TransformState::make_identity();
   } else {
     CPT(TransformState) transform = comp->get_node()->get_prev_transform();
-    int pipeline_stage = Thread::get_current_pipeline_stage();
-    return r_get_net_prev_transform(comp->get_next(pipeline_stage))->compose(transform);
+    int pipeline_stage = current_thread->get_pipeline_stage();
+    return r_get_net_prev_transform(comp->get_next(pipeline_stage, current_thread), current_thread)->compose(transform);
   }
 }
 
@@ -5794,13 +5807,13 @@ r_get_net_prev_transform(NodePathComponent *comp) const {
 //               the graph.
 ////////////////////////////////////////////////////////////////////
 CPT(TransformState) NodePath::
-r_get_partial_prev_transform(NodePathComponent *comp, int n) const {
+r_get_partial_prev_transform(NodePathComponent *comp, int n, Thread *current_thread) const {
   if (n == 0 || comp == (NodePathComponent *)NULL) {
     return TransformState::make_identity();
   } else {
     CPT(TransformState) transform = comp->get_node()->get_prev_transform();
-    int pipeline_stage = Thread::get_current_pipeline_stage();
-    return r_get_partial_prev_transform(comp->get_next(pipeline_stage), n - 1)->compose(transform);
+    int pipeline_stage = current_thread->get_pipeline_stage();
+    return r_get_partial_prev_transform(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread)->compose(transform);
   }
 }
 

+ 77 - 60
panda/src/pgraph/nodePath.h

@@ -163,10 +163,11 @@ PUBLISHED:
   };
 
   INLINE NodePath();
-  INLINE NodePath(const string &top_node_name);
-  INLINE NodePath(PandaNode *node);
-  INLINE static NodePath any_path(PandaNode *node);
-  INLINE NodePath(const NodePath &parent, PandaNode *child_node);
+  INLINE NodePath(const string &top_node_name, Thread *current_thread = Thread::get_current_thread());
+  INLINE NodePath(PandaNode *node, Thread *current_thread = Thread::get_current_thread());
+  INLINE static NodePath any_path(PandaNode *node, Thread *current_thread = Thread::get_current_thread());
+  INLINE NodePath(const NodePath &parent, PandaNode *child_node,
+                  Thread *current_thread = Thread::get_current_thread());
 
   INLINE NodePath(const NodePath &copy);
   INLINE void operator = (const NodePath &copy);
@@ -180,34 +181,34 @@ PUBLISHED:
 
   // Methods to query a NodePath's contents.
   INLINE bool is_empty() const;
-  INLINE bool is_singleton() const;
-  int get_num_nodes() const;
-  PandaNode *get_node(int index) const;
+  INLINE bool is_singleton(Thread *current_thread = Thread::get_current_thread()) const;
+  int get_num_nodes(Thread *current_thread = Thread::get_current_thread()) const;
+  PandaNode *get_node(int index, Thread *current_thread = Thread::get_current_thread()) const;
 
   INLINE ErrorType get_error_type() const;
 
-  PandaNode *get_top_node() const;
-  NodePath get_top() const;
+  INLINE PandaNode *get_top_node(Thread *current_thread = Thread::get_current_thread()) const;
+  NodePath get_top(Thread *current_thread = Thread::get_current_thread()) const;
 
   INLINE PandaNode *node() const;
 
   INLINE int get_key() const;
 
-  INLINE bool is_same_graph(const NodePath &other) const;
-  INLINE bool is_ancestor_of(const NodePath &other) const;
-  INLINE NodePath get_common_ancestor(const NodePath &other) const;
+  INLINE bool is_same_graph(const NodePath &other, Thread *current_thread = Thread::get_current_thread()) const;
+  INLINE bool is_ancestor_of(const NodePath &other, Thread *current_thread = Thread::get_current_thread()) const;
+  INLINE NodePath get_common_ancestor(const NodePath &other, Thread *current_thread = Thread::get_current_thread()) const;
 
   // Methods that return collections of NodePaths derived from or
   // related to this one.
 
-  NodePathCollection get_children() const;
-  INLINE int get_num_children() const;
-  INLINE NodePath get_child(int n) const;
-  NodePathCollection get_stashed_children() const;
+  NodePathCollection get_children(Thread *current_thread = Thread::get_current_thread()) const;
+  INLINE int get_num_children(Thread *current_thread = Thread::get_current_thread()) const;
+  INLINE NodePath get_child(int n, Thread *current_thread = Thread::get_current_thread()) const;
+  NodePathCollection get_stashed_children(Thread *current_thread = Thread::get_current_thread()) const;
 
-  INLINE bool has_parent() const;
-  INLINE NodePath get_parent() const;
-  int get_sort() const;
+  INLINE bool has_parent(Thread *current_thread = Thread::get_current_thread()) const;
+  INLINE NodePath get_parent(Thread *current_thread = Thread::get_current_thread()) const;
+  int get_sort(Thread *current_thread = Thread::get_current_thread()) const;
 
   NodePath find(const string &path) const;
   NodePath find_path_to(PandaNode *node) const;
@@ -219,16 +220,23 @@ PUBLISHED:
   // ordering between sibling nodes, useful when dealing with LOD's
   // and similar switch nodes.  If the sort value is the same, nodes
   // will be arranged in the order they were added.
-  void reparent_to(const NodePath &other, int sort = 0);
-  void wrt_reparent_to(const NodePath &other, int sort = 0);
-  NodePath instance_to(const NodePath &other, int sort = 0) const;
+  void reparent_to(const NodePath &other, int sort = 0,
+                   Thread *current_thread = Thread::get_current_thread());
+  void wrt_reparent_to(const NodePath &other, int sort = 0,
+                       Thread *current_thread = Thread::get_current_thread());
+  NodePath instance_to(const NodePath &other, int sort = 0,
+                       Thread *current_thread = Thread::get_current_thread()) const;
   NodePath instance_under_node(const NodePath &other, const string &name,
-                                 int sort = 0) const;
-  NodePath copy_to(const NodePath &other, int sort = 0) const;
-  NodePath attach_new_node(PandaNode *node, int sort = 0) const;
-  INLINE NodePath attach_new_node(const string &name, int sort = 0) const;
-  void remove_node();
-  void detach_node();
+                               int sort = 0,
+                               Thread *current_thread = Thread::get_current_thread()) const;
+  NodePath copy_to(const NodePath &other, int sort = 0,
+                   Thread *current_thread = Thread::get_current_thread()) const;
+  NodePath attach_new_node(PandaNode *node, int sort = 0,
+                           Thread *current_thread = Thread::get_current_thread()) const;
+  INLINE NodePath attach_new_node(const string &name, int sort = 0,
+                                  Thread *current_thread = Thread::get_current_thread()) const;
+  void remove_node(Thread *current_thread = Thread::get_current_thread());
+  void detach_node(Thread *current_thread = Thread::get_current_thread());
 
   // Handy ways to look at what's there, and other miscellaneous
   // operations.
@@ -242,11 +250,11 @@ PUBLISHED:
 
 
   // Aggregate transform and state information.
-  const RenderState *get_state() const;
-  INLINE void set_state(const RenderState *state);
-  CPT(RenderState) get_state(const NodePath &other) const;
-  void set_state(const NodePath &other, const RenderState *state);
-  INLINE CPT(RenderState) get_net_state() const;
+  const RenderState *get_state(Thread *current_thread = Thread::get_current_thread()) const;
+  INLINE void set_state(const RenderState *state, Thread *current_thread = Thread::get_current_thread());
+  CPT(RenderState) get_state(const NodePath &other, Thread *current_thread = Thread::get_current_thread()) const;
+  void set_state(const NodePath &other, const RenderState *state, Thread *current_thread = Thread::get_current_thread());
+  INLINE CPT(RenderState) get_net_state(Thread *current_thread = Thread::get_current_thread()) const;
 
   INLINE void set_attrib(const RenderAttrib *attrib, int priority = 0);
   INLINE const RenderAttrib *get_attrib(TypeHandle type) const;
@@ -262,19 +270,19 @@ PUBLISHED:
   INLINE const RenderEffects *get_effects() const;
   INLINE void clear_effects();
 
-  const TransformState *get_transform() const;
-  INLINE void clear_transform();
-  INLINE void set_transform(const TransformState *transform);
-  CPT(TransformState) get_transform(const NodePath &other) const;
-  INLINE void clear_transform(const NodePath &other);
-  void set_transform(const NodePath &other, const TransformState *transform);
-  INLINE CPT(TransformState) get_net_transform() const;
+  const TransformState *get_transform(Thread *current_thread = Thread::get_current_thread()) const;
+  INLINE void clear_transform(Thread *current_thread = Thread::get_current_thread());
+  INLINE void set_transform(const TransformState *transform, Thread *current_thread = Thread::get_current_thread());
+  CPT(TransformState) get_transform(const NodePath &other, Thread *current_thread = Thread::get_current_thread()) const;
+  INLINE void clear_transform(const NodePath &other, Thread *current_thread = Thread::get_current_thread());
+  void set_transform(const NodePath &other, const TransformState *transform, Thread *current_thread = Thread::get_current_thread());
+  INLINE CPT(TransformState) get_net_transform(Thread *current_thread = Thread::get_current_thread()) const;
 
-  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;
+  const TransformState *get_prev_transform(Thread *current_thread = Thread::get_current_thread()) const;
+  INLINE void set_prev_transform(const TransformState *transform, Thread *current_thread = Thread::get_current_thread());
+  CPT(TransformState) get_prev_transform(const NodePath &other, Thread *current_thread = Thread::get_current_thread()) const;
+  void set_prev_transform(const NodePath &other, const TransformState *transform, Thread *current_thread = Thread::get_current_thread());
+  INLINE CPT(TransformState) get_net_prev_transform(Thread *current_thread = Thread::get_current_thread()) const;
 
 
   // Methods that get and set the matrix transform: pos, hpr, scale,
@@ -743,13 +751,14 @@ PUBLISHED:
   INLINE void hide();
   INLINE void hide(DrawMask camera_mask);
   INLINE bool is_hidden(DrawMask camera_mask = PandaNode::get_overall_bit()) const;
-  NodePath get_hidden_ancestor(DrawMask camera_mask = PandaNode::get_overall_bit()) const;
+  NodePath get_hidden_ancestor(DrawMask camera_mask = PandaNode::get_overall_bit(),
+                               Thread *current_thread = Thread::get_current_thread()) const;
 
-  void stash(int sort = 0);
-  void unstash(int sort = 0);
-  void unstash_all();
+  void stash(int sort = 0, Thread *current_thread = Thread::get_current_thread());
+  void unstash(int sort = 0, Thread *current_thread = Thread::get_current_thread());
+  void unstash_all(Thread *current_thread = Thread::get_current_thread());
   INLINE bool is_stashed() const;
-  NodePath get_stashed_ancestor() const;
+  NodePath get_stashed_ancestor(Thread *current_thread = Thread::get_current_thread()) const;
 
   INLINE CollideMask get_collide_mask() const;
   INLINE void set_collide_mask(CollideMask new_mask, CollideMask bits_to_change = CollideMask::all_on(),
@@ -762,7 +771,7 @@ PUBLISHED:
   INLINE int compare_to(const NodePath &other) const;
 
   // Miscellaneous
-  bool verify_complete() const;
+  bool verify_complete(Thread *current_thread = Thread::get_current_thread()) const;
 
   void prepare_scene(GraphicsStateGuardianBase *gsg);
 
@@ -772,7 +781,8 @@ PUBLISHED:
   PT(BoundingVolume) get_bounds() const;
   void force_recompute_bounds();
   void write_bounds(ostream &out) const;
-  bool calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point);
+  bool calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
+                         Thread *current_thread = Thread::get_current_thread());
 
   void analyze() const;
 
@@ -808,14 +818,21 @@ PUBLISHED:
 private:
   static NodePathComponent *
   find_common_ancestor(const NodePath &a, const NodePath &b,
-                       int &a_count, int &b_count);
-
-  CPT(RenderState) r_get_net_state(NodePathComponent *comp) 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_partial_transform(NodePathComponent *comp, int n) const;
-  CPT(TransformState) r_get_net_prev_transform(NodePathComponent *comp) const;
-  CPT(TransformState) r_get_partial_prev_transform(NodePathComponent *comp, int n) const;
+                       int &a_count, int &b_count, 
+                       Thread *current_thread);
+
+  CPT(RenderState) r_get_net_state(NodePathComponent *comp, 
+                                   Thread *current_thread) const;
+  CPT(RenderState) r_get_partial_state(NodePathComponent *comp, int n,
+                                       Thread *current_thread) const;
+  CPT(TransformState) r_get_net_transform(NodePathComponent *comp, 
+                                          Thread *current_thread) const;
+  CPT(TransformState) r_get_partial_transform(NodePathComponent *comp, int n,
+                                              Thread *current_thread) const;
+  CPT(TransformState) r_get_net_prev_transform(NodePathComponent *comp,
+                                               Thread *current_thread) const;
+  CPT(TransformState) r_get_partial_prev_transform(NodePathComponent *comp, 
+                                                   int n, Thread *current_thread) const;
 
   void find_matches(NodePathCollection &result,
                     const string &approx_path_str,

+ 19 - 18
panda/src/pgraph/nodePathComponent.cxx

@@ -45,7 +45,7 @@ make_copy() const {
 ////////////////////////////////////////////////////////////////////
 NodePathComponent::
 NodePathComponent(PandaNode *node, NodePathComponent *next,
-		  int pipeline_stage) :
+		  int pipeline_stage, Thread *current_thread) :
   _node(node),
   _key(0)
 {
@@ -56,11 +56,11 @@ NodePathComponent(PandaNode *node, NodePathComponent *next,
   for (int pipeline_stage_i = pipeline_stage;
        pipeline_stage_i >= 0; 
        --pipeline_stage_i) {
-    CDStageWriter cdata(_cycler, pipeline_stage_i);
+    CDStageWriter cdata(_cycler, pipeline_stage_i, current_thread);
     cdata->_next = next;
     
     if (next != (NodePathComponent *)NULL) {
-      cdata->_length = next->get_length(pipeline_stage_i) + 1;
+      cdata->_length = next->get_length(pipeline_stage_i, current_thread) + 1;
     }
   }
 }
@@ -94,8 +94,8 @@ get_key() const {
 //               node in the path.
 ////////////////////////////////////////////////////////////////////
 bool NodePathComponent::
-is_top_node(int pipeline_stage) const {
-  CDStageReader cdata(_cycler, pipeline_stage);
+is_top_node(int pipeline_stage, Thread *current_thread) const {
+  CDStageReader cdata(_cycler, pipeline_stage, current_thread);
   return (cdata->_next == (NodePathComponent *)NULL);
 }
 
@@ -105,8 +105,8 @@ is_top_node(int pipeline_stage) const {
 //  Description: Returns the length of the path to this node.
 ////////////////////////////////////////////////////////////////////
 int NodePathComponent::
-get_length(int pipeline_stage) const {
-  CDStageReader cdata(_cycler, pipeline_stage);
+get_length(int pipeline_stage, Thread *current_thread) const {
+  CDStageReader cdata(_cycler, pipeline_stage, current_thread);
   return cdata->_length;
 }
 
@@ -116,8 +116,8 @@ get_length(int pipeline_stage) const {
 //  Description: Returns the next component in the path.
 ////////////////////////////////////////////////////////////////////
 NodePathComponent *NodePathComponent::
-get_next(int pipeline_stage) const {
-  CDStageReader cdata(_cycler, pipeline_stage);
+get_next(int pipeline_stage, Thread *current_thread) const {
+  CDStageReader cdata(_cycler, pipeline_stage, current_thread);
   NodePathComponent *next = cdata->_next;
   
   return next;
@@ -132,12 +132,12 @@ get_next(int pipeline_stage) const {
 //               component has been changed; otherwise, returns false.
 ////////////////////////////////////////////////////////////////////
 bool NodePathComponent::
-fix_length(int pipeline_stage) {
-  CDStageReader cdata(_cycler, pipeline_stage);
+fix_length(int pipeline_stage, Thread *current_thread) {
+  CDStageReader cdata(_cycler, pipeline_stage, current_thread);
 
   int length_should_be = 1;
   if (cdata->_next != (NodePathComponent *)NULL) {
-    length_should_be = cdata->_next->get_length(pipeline_stage) + 1;
+    length_should_be = cdata->_next->get_length(pipeline_stage, current_thread) + 1;
   }
 
   if (cdata->_length == length_should_be) {
@@ -159,10 +159,11 @@ fix_length(int pipeline_stage) {
 ////////////////////////////////////////////////////////////////////
 void NodePathComponent::
 output(ostream &out) const {
-  int pipeline_stage = Thread::get_current_pipeline_stage();
+  Thread *current_thread = Thread::get_current_thread();
+  int pipeline_stage = current_thread->get_pipeline_stage();
 
   PandaNode *node = get_node();
-  NodePathComponent *next = get_next(pipeline_stage);
+  NodePathComponent *next = get_next(pipeline_stage, current_thread);
   if (next != (NodePathComponent *)NULL) {
     // This is not the head of the list; keep going up.
     next->output(out);
@@ -194,9 +195,9 @@ output(ostream &out) const {
 //  Description: Sets the next pointer in the path.
 ////////////////////////////////////////////////////////////////////
 void NodePathComponent::
-set_next(NodePathComponent *next, int pipeline_stage) {
+set_next(NodePathComponent *next, int pipeline_stage, Thread *current_thread) {
   nassertv(next != (NodePathComponent *)NULL);
-  CDStageWriter cdata(_cycler, pipeline_stage);
+  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
   cdata->_next = next;
 }
 
@@ -207,7 +208,7 @@ set_next(NodePathComponent *next, int pipeline_stage) {
 //               path and makes this component a top node.
 ////////////////////////////////////////////////////////////////////
 void NodePathComponent::
-set_top_node(int pipeline_stage) {
-  CDStageWriter cdata(_cycler, pipeline_stage);
+set_top_node(int pipeline_stage, Thread *current_thread) {
+  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
   cdata->_next = (NodePathComponent *)NULL;
 }

+ 7 - 7
panda/src/pgraph/nodePathComponent.h

@@ -51,7 +51,7 @@
 class EXPCL_PANDA NodePathComponent : public ReferenceCount {
 private:
   NodePathComponent(PandaNode *node, NodePathComponent *next,
-		    int pipeline_stage);
+		    int pipeline_stage, Thread *current_thread);
   INLINE NodePathComponent(const NodePathComponent &copy);
   INLINE void operator = (const NodePathComponent &copy);
 
@@ -62,18 +62,18 @@ public:
   INLINE PandaNode *get_node() const;
   INLINE bool has_key() const;
   int get_key() const;
-  bool is_top_node(int pipeline_stage) const;
+  bool is_top_node(int pipeline_stage, Thread *current_thread) const;
   
-  NodePathComponent *get_next(int pipeline_stage) const;
-  int get_length(int pipeline_stage) const;
+  NodePathComponent *get_next(int pipeline_stage, Thread *current_thread) const;
+  int get_length(int pipeline_stage, Thread *current_thread) const;
 
-  bool fix_length(int pipeline_stage);
+  bool fix_length(int pipeline_stage, Thread *current_thread);
 
   void output(ostream &out) const;
   
 private:
-  void set_next(NodePathComponent *next, int pipeline_stage);
-  void set_top_node(int pipeline_stage);
+  void set_next(NodePathComponent *next, int pipeline_stage, Thread *current_thread);
+  void set_top_node(int pipeline_stage, Thread *current_thread);
 
   // We don't have to cycle the _node and _key elements, since these
   // are permanent properties of this object.  (Well, the _key is

+ 118 - 56
panda/src/pgraph/pandaNode.I

@@ -40,15 +40,15 @@ compose_draw_mask(DrawMask &running_draw_mask) const {
 //               be visible to the indicated camera_mask.
 ////////////////////////////////////////////////////////////////////
 INLINE bool PandaNode::
-compare_draw_mask(DrawMask running_draw_mask, DrawMask camera_mask) const {
+compare_draw_mask(DrawMask running_draw_mask, DrawMask camera_mask,
+                  Thread *current_thread) const {
   DrawMask net_draw_control_mask, net_draw_show_mask;
 
-  int pipeline_stage = Thread::get_current_pipeline_stage();
-  CDBoundsStageReader cdata(_cycler_bounds, pipeline_stage);
+  int pipeline_stage = current_thread->get_pipeline_stage();
+  CDBoundsStageReader cdata(_cycler_bounds, pipeline_stage, current_thread);
   if (cdata->_last_update != cdata->_next_update) {
     // The cache is stale; it needs to be rebuilt.
-    CDBoundsStageWriter cdataw = 
-      ((PandaNode *)this)->update_bounds(pipeline_stage, cdata); 
+    CDBoundsStageWriter cdataw = ((PandaNode *)this)->update_bounds(pipeline_stage, cdata); 
     net_draw_control_mask = cdataw->_net_draw_control_mask;
     net_draw_show_mask = cdataw->_net_draw_show_mask;
   } else {
@@ -84,8 +84,8 @@ compare_draw_mask(DrawMask running_draw_mask, DrawMask camera_mask) const {
 //               which the node was instanced to them.
 ////////////////////////////////////////////////////////////////////
 INLINE int PandaNode::
-get_num_parents() const {
-  CDLinksReader cdata(_cycler_links);
+get_num_parents(Thread *current_thread) const {
+  CDLinksReader cdata(_cycler_links, current_thread);
   return cdata->get_up()->size();
 }
 
@@ -98,8 +98,8 @@ get_num_parents() const {
 //               parents; get_parents() is preferable in this case.
 ////////////////////////////////////////////////////////////////////
 INLINE PandaNode *PandaNode::
-get_parent(int n) const {
-  CDLinksReader cdata(_cycler_links);
+get_parent(int n, Thread *current_thread) const {
+  CDLinksReader cdata(_cycler_links, current_thread);
   const Up &up = *cdata->get_up();
   nassertr(n >= 0 && n < (int)up.size(), NULL);
   return up[n].get_parent();
@@ -112,8 +112,8 @@ get_parent(int n) const {
 //               is a parent, or -1 if it is not.
 ////////////////////////////////////////////////////////////////////
 INLINE int PandaNode::
-find_parent(PandaNode *node) const {
-  CDLinksReader cdata(_cycler_links);
+find_parent(PandaNode *node, Thread *current_thread) const {
+  CDLinksReader cdata(_cycler_links, current_thread);
   return do_find_parent(node, cdata);
 }
 
@@ -126,8 +126,8 @@ find_parent(PandaNode *node) const {
 //               and also on the order in which the nodes were added.
 ////////////////////////////////////////////////////////////////////
 INLINE int PandaNode::
-get_num_children() const {
-  CDLinksReader cdata(_cycler_links);
+get_num_children(Thread *current_thread) const {
+  CDLinksReader cdata(_cycler_links, current_thread);
   return cdata->get_down()->size();
 }
 
@@ -140,8 +140,8 @@ get_num_children() const {
 //               children; get_children() is preferable in this case.
 ////////////////////////////////////////////////////////////////////
 INLINE PandaNode *PandaNode::
-get_child(int n) const {
-  CDLinksReader cdata(_cycler_links);
+get_child(int n, Thread *current_thread) const {
+  CDLinksReader cdata(_cycler_links, current_thread);
   const Down &down = *cdata->get_down();
   nassertr(n >= 0 && n < (int)down.size(), NULL);
   return down[n].get_child();
@@ -155,8 +155,8 @@ get_child(int n) const {
 //               add_child()).  See get_num_children().
 ////////////////////////////////////////////////////////////////////
 INLINE int PandaNode::
-get_child_sort(int n) const {
-  CDLinksReader cdata(_cycler_links);
+get_child_sort(int n, Thread *current_thread) const {
+  CDLinksReader cdata(_cycler_links, current_thread);
   const Down &down = *cdata->get_down();
   nassertr(n >= 0 && n < (int)down.size(), -1);
   return down[n].get_sort();
@@ -169,8 +169,8 @@ get_child_sort(int n) const {
 //               is a child, or -1 if it is not.
 ////////////////////////////////////////////////////////////////////
 INLINE int PandaNode::
-find_child(PandaNode *node) const {
-  CDLinksReader cdata(_cycler_links);
+find_child(PandaNode *node, Thread *current_thread) const {
+  CDLinksReader cdata(_cycler_links, current_thread);
   return do_find_child(node, cdata);
 }
 
@@ -191,12 +191,12 @@ find_child(PandaNode *node) const {
 //               previously stashed).
 ////////////////////////////////////////////////////////////////////
 INLINE bool PandaNode::
-stash_child(PandaNode *child_node) {
-  int child_index = find_child(child_node);
+stash_child(PandaNode *child_node, Thread *current_thread) {
+  int child_index = find_child(child_node, current_thread);
   if (child_index < 0) {
     return false;
   }
-  stash_child(child_index);
+  stash_child(child_index, current_thread);
   return true;
 }
 
@@ -217,12 +217,12 @@ stash_child(PandaNode *child_node) {
 //               previously stashed).
 ////////////////////////////////////////////////////////////////////
 INLINE bool PandaNode::
-unstash_child(PandaNode *child_node) {
-  int stashed_index = find_stashed(child_node);
+unstash_child(PandaNode *child_node, Thread *current_thread) {
+  int stashed_index = find_stashed(child_node, current_thread);
   if (stashed_index < 0) {
     return false;
   }
-  unstash_child(stashed_index);
+  unstash_child(stashed_index, current_thread);
   return true;
 }
 
@@ -234,8 +234,8 @@ unstash_child(PandaNode *child_node) {
 //               moved to the special stashed list via stash_child().
 ////////////////////////////////////////////////////////////////////
 INLINE int PandaNode::
-get_num_stashed() const {
-  CDLinksReader cdata(_cycler_links);
+get_num_stashed(Thread *current_thread) const {
+  CDLinksReader cdata(_cycler_links, current_thread);
   return cdata->get_stashed()->size();
 }
 
@@ -249,8 +249,8 @@ get_num_stashed() const {
 //               case.
 ////////////////////////////////////////////////////////////////////
 INLINE PandaNode *PandaNode::
-get_stashed(int n) const {
-  CDLinksReader cdata(_cycler_links);
+get_stashed(int n, Thread *current_thread) const {
+  CDLinksReader cdata(_cycler_links, current_thread);
   const Down &stashed = *cdata->get_stashed();
   nassertr(n >= 0 && n < (int)stashed.size(), NULL);
   return stashed[n].get_child();
@@ -264,8 +264,8 @@ get_stashed(int n) const {
 //               add_child()).  See get_num_stashed().
 ////////////////////////////////////////////////////////////////////
 INLINE int PandaNode::
-get_stashed_sort(int n) const {
-  CDLinksReader cdata(_cycler_links);
+get_stashed_sort(int n, Thread *current_thread) const {
+  CDLinksReader cdata(_cycler_links, current_thread);
   const Down &stashed = *cdata->get_stashed();
   nassertr(n >= 0 && n < (int)stashed.size(), -1);
   return stashed[n].get_sort();
@@ -278,8 +278,8 @@ get_stashed_sort(int n) const {
 //               it is a stashed child, or -1 if it is not.
 ////////////////////////////////////////////////////////////////////
 INLINE int PandaNode::
-find_stashed(PandaNode *node) const {
-  CDLinksReader cdata(_cycler_links);
+find_stashed(PandaNode *node, Thread *current_thread) const {
+  CDLinksReader cdata(_cycler_links, current_thread);
   return do_find_stashed(node, cdata);
 }
 
@@ -356,8 +356,8 @@ has_effect(TypeHandle type) const {
 //               that might be inherited from above.
 ////////////////////////////////////////////////////////////////////
 INLINE const RenderState *PandaNode::
-get_state() const {
-  CDLightReader cdata(_cycler_light);
+get_state(Thread *current_thread) const {
+  CDLightReader cdata(_cycler_light, current_thread);
   return cdata->_state;
 }
 
@@ -370,8 +370,8 @@ get_state() const {
 //               this level.
 ////////////////////////////////////////////////////////////////////
 INLINE void PandaNode::
-clear_state() {
-  set_state(RenderState::make_empty());
+clear_state(Thread *current_thread) {
+  set_state(RenderState::make_empty(), current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -405,8 +405,8 @@ clear_effects() {
 //               node.
 ////////////////////////////////////////////////////////////////////
 INLINE const TransformState *PandaNode::
-get_transform() const {
-  CDLightReader cdata(_cycler_light);
+get_transform(Thread *current_thread) const {
+  CDLightReader cdata(_cycler_light, current_thread);
   return cdata->_transform;
 }
 
@@ -417,8 +417,8 @@ get_transform() const {
 //               transform.
 ////////////////////////////////////////////////////////////////////
 INLINE void PandaNode::
-clear_transform() {
-  set_transform(TransformState::make_identity());
+clear_transform(Thread *current_thread) {
+  set_transform(TransformState::make_identity(), current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -429,8 +429,8 @@ clear_transform() {
 //               set_prev_transform().
 ////////////////////////////////////////////////////////////////////
 const TransformState *PandaNode::
-get_prev_transform() const {
-  CDLightReader cdata(_cycler_light);
+get_prev_transform(Thread *current_thread) const {
+  CDLightReader cdata(_cycler_light, current_thread);
   return cdata->_prev_transform;
 }
 
@@ -620,8 +620,9 @@ clear_bounds() {
 ////////////////////////////////////////////////////////////////////
 INLINE CPT(BoundingVolume) PandaNode::
 get_internal_bounds() const {
-  int pipeline_stage = Thread::get_current_pipeline_stage();
-  return get_internal_bounds(pipeline_stage);
+  Thread *current_thread = Thread::get_current_thread();
+  return get_internal_bounds(current_thread->get_pipeline_stage(),
+                             current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -670,8 +671,8 @@ is_final() const {
 //               never been set.
 ////////////////////////////////////////////////////////////////////
 INLINE CPT(BoundingVolume) PandaNode::
-get_user_bounds(int pipeline_stage) const {
-  CDHeavyStageReader cdata(_cycler_heavy, pipeline_stage);
+get_user_bounds(int pipeline_stage, Thread *current_thread) const {
+  CDHeavyStageReader cdata(_cycler_heavy, pipeline_stage, current_thread);
   return cdata->_user_bounds;
 }
 
@@ -685,16 +686,16 @@ get_user_bounds(int pipeline_stage) const {
 //               recomputed.
 ////////////////////////////////////////////////////////////////////
 INLINE void PandaNode::
-mark_bounds_stale(int pipeline_stage) const {
+mark_bounds_stale(int pipeline_stage, Thread *current_thread) const {
   // It's important that we don't hold the lock during the call to
   // force_bounds_stale().
   bool is_stale_bounds;
   {
-    CDBoundsStageReader cdata(_cycler_bounds, pipeline_stage);
+    CDBoundsStageReader cdata(_cycler_bounds, pipeline_stage, current_thread);
     is_stale_bounds = (cdata->_last_update != cdata->_next_update);
   }
   if (!is_stale_bounds) {
-    ((PandaNode *)this)->force_bounds_stale(pipeline_stage);
+    ((PandaNode *)this)->force_bounds_stale(pipeline_stage, current_thread);
   }
 }
 
@@ -708,12 +709,12 @@ mark_bounds_stale(int pipeline_stage) const {
 //               bounding volume is next requested.
 ////////////////////////////////////////////////////////////////////
 INLINE void PandaNode::
-mark_internal_bounds_stale(int pipeline_stage) {
+mark_internal_bounds_stale(int pipeline_stage, Thread *current_thread) {
   {
-    CDHeavyWriter cdata(_cycler_heavy);
+    CDHeavyStageWriter cdata(_cycler_heavy, pipeline_stage, current_thread);
     cdata->_internal_bounds_stale = true;
   }
-  mark_bounds_stale(pipeline_stage);
+  mark_bounds_stale(pipeline_stage, current_thread);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1048,7 +1049,16 @@ modify_up() {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE PandaNode::Children::
-Children(const PandaNode::CDLinksReader &cdata) :
+Children() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::Children::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE PandaNode::Children::
+Children(const PandaNode::CDataLinks *cdata) :
   _down(cdata->get_down())
 {
 }
@@ -1081,6 +1091,7 @@ operator = (const PandaNode::Children &copy) {
 ////////////////////////////////////////////////////////////////////
 INLINE int PandaNode::Children::
 get_num_children() const {
+  nassertr(_down != (Down *)NULL, 0);
   return _down->size();
 }
 
@@ -1091,17 +1102,41 @@ get_num_children() const {
 ////////////////////////////////////////////////////////////////////
 INLINE PandaNode *PandaNode::Children::
 get_child(int n) const {
+  nassertr(_down != (Down *)NULL, NULL);
   nassertr(n >= 0 && n < (int)_down->size(), NULL);
   return (*_down)[n].get_child();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::Children::get_child_sort
+//       Access: Public
+//  Description: Returns the sort index of the nth child node of this
+//               node (that is, the number that was passed to
+//               add_child()).  See get_num_children().
+////////////////////////////////////////////////////////////////////
+INLINE int PandaNode::Children::
+get_child_sort(int n) const {
+  nassertr(_down != (Down *)NULL, -1);
+  nassertr(n >= 0 && n < (int)_down->size(), -1);
+  return (*_down)[n].get_sort();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PandaNode::Stashed::Constructor
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE PandaNode::Stashed::
-Stashed(const PandaNode::CDLinksReader &cdata) :
+Stashed() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::Stashed::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE PandaNode::Stashed::
+Stashed(const PandaNode::CDataLinks *cdata) :
   _stashed(cdata->get_stashed())
 {
 }
@@ -1134,6 +1169,7 @@ operator = (const PandaNode::Stashed &copy) {
 ////////////////////////////////////////////////////////////////////
 INLINE int PandaNode::Stashed::
 get_num_stashed() const {
+  nassertr(_stashed != (Down *)NULL, 0);
   return _stashed->size();
 }
 
@@ -1144,17 +1180,41 @@ get_num_stashed() const {
 ////////////////////////////////////////////////////////////////////
 INLINE PandaNode *PandaNode::Stashed::
 get_stashed(int n) const {
+  nassertr(_stashed != (Down *)NULL, NULL);
   nassertr(n >= 0 && n < (int)_stashed->size(), NULL);
   return (*_stashed)[n].get_child();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::Stashed::get_stashed_sort
+//       Access: Public
+//  Description: Returns the sort index of the nth child node of this
+//               node (that is, the number that was passed to
+//               add_child()).  See get_num_stashed().
+////////////////////////////////////////////////////////////////////
+INLINE int PandaNode::Stashed::
+get_stashed_sort(int n) const {
+  nassertr(_stashed != (Down *)NULL, -1);
+  nassertr(n >= 0 && n < (int)_stashed->size(), -1);
+  return (*_stashed)[n].get_sort();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::Parents::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE PandaNode::Parents::
+Parents() {
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PandaNode::Parents::Constructor
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE PandaNode::Parents::
-Parents(const PandaNode::CDLinksReader &cdata) :
+Parents(const PandaNode::CDataLinks *cdata) :
   _up(cdata->get_up())
 {
 }
@@ -1187,6 +1247,7 @@ operator = (const PandaNode::Parents &copy) {
 ////////////////////////////////////////////////////////////////////
 INLINE int PandaNode::Parents::
 get_num_parents() const {
+  nassertr(_up != (Up *)NULL, 0);
   return _up->size();
 }
 
@@ -1197,6 +1258,7 @@ get_num_parents() const {
 ////////////////////////////////////////////////////////////////////
 INLINE PandaNode *PandaNode::Parents::
 get_parent(int n) const {
+  nassertr(_up != (Up *)NULL, NULL);
   nassertr(n >= 0 && n < (int)_up->size(), NULL);
   return (*_up)[n].get_parent();
 }

File diff suppressed because it is too large
+ 179 - 167
panda/src/pgraph/pandaNode.cxx


+ 90 - 74
panda/src/pgraph/pandaNode.h

@@ -98,7 +98,8 @@ public:
   virtual CPT(TransformState)
     calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
                       bool &found_any,
-                      const TransformState *transform) const;
+                      const TransformState *transform,
+                      Thread *current_thread) const;
   
   virtual bool has_cull_callback() const;
   virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data);
@@ -111,41 +112,48 @@ public:
 
   INLINE void compose_draw_mask(DrawMask &running_draw_mask) const;
   INLINE bool compare_draw_mask(DrawMask running_draw_mask,
-                                DrawMask camera_mask) const;
+                                DrawMask camera_mask, 
+                                Thread *current_thread) const;
 
 PUBLISHED:
-  PT(PandaNode) copy_subgraph() const;
-
-  INLINE int get_num_parents() const;
-  INLINE PandaNode *get_parent(int n) const;
-  INLINE int find_parent(PandaNode *node) const;
-
-  INLINE int get_num_children() const;
-  INLINE PandaNode *get_child(int n) const;
-  INLINE int get_child_sort(int n) const;
-  INLINE int find_child(PandaNode *node) const;
-
-  void add_child(PandaNode *child_node, int sort = 0);
-  void remove_child(int child_index);
-  bool remove_child(PandaNode *child_node);
-  bool replace_child(PandaNode *orig_child, PandaNode *new_child);
-
-  INLINE bool stash_child(PandaNode *child_node);
-  void stash_child(int child_index);
-  INLINE bool unstash_child(PandaNode *child_node);
-  void unstash_child(int stashed_index);
-
-  INLINE int get_num_stashed() const;
-  INLINE PandaNode *get_stashed(int n) const;
-  INLINE int get_stashed_sort(int n) const;
-  INLINE int find_stashed(PandaNode *node) const;
-
-  void add_stashed(PandaNode *child_node, int sort = 0);
-  void remove_stashed(int child_index);
-
-  void remove_all_children();
-  void steal_children(PandaNode *other);
-  void copy_children(PandaNode *other);
+  PT(PandaNode) copy_subgraph(Thread *current_thread = Thread::get_current_thread()) const;
+
+  INLINE int get_num_parents(Thread *current_thread = Thread::get_current_thread()) const;
+  INLINE PandaNode *get_parent(int n, Thread *current_thread = Thread::get_current_thread()) const;
+  INLINE int find_parent(PandaNode *node, Thread *current_thread = Thread::get_current_thread()) const;
+
+  INLINE int get_num_children(Thread *current_thread = Thread::get_current_thread()) const;
+  INLINE PandaNode *get_child(int n, Thread *current_thread = Thread::get_current_thread()) const;
+  INLINE int get_child_sort(int n, Thread *current_thread = Thread::get_current_thread()) const;
+  INLINE int find_child(PandaNode *node, Thread *current_thread = Thread::get_current_thread()) const;
+
+  void add_child(PandaNode *child_node, int sort = 0,
+                 Thread *current_thread = Thread::get_current_thread());
+  void remove_child(int child_index, Thread *current_thread = Thread::get_current_thread());
+  bool remove_child(PandaNode *child_node, Thread *current_thread = Thread::get_current_thread());
+  bool replace_child(PandaNode *orig_child, PandaNode *new_child,
+                     Thread *current_thread = Thread::get_current_thread());
+
+  INLINE bool stash_child(PandaNode *child_node,
+                          Thread *current_thread = Thread::get_current_thread());
+  void stash_child(int child_index,
+                   Thread *current_thread = Thread::get_current_thread());
+  INLINE bool unstash_child(PandaNode *child_node,
+                            Thread *current_thread = Thread::get_current_thread());
+  void unstash_child(int stashed_index,
+                     Thread *current_thread = Thread::get_current_thread());
+
+  INLINE int get_num_stashed(Thread *current_thread = Thread::get_current_thread()) const;
+  INLINE PandaNode *get_stashed(int n, Thread *current_thread = Thread::get_current_thread()) const;
+  INLINE int get_stashed_sort(int n, Thread *current_thread = Thread::get_current_thread()) const;
+  INLINE int find_stashed(PandaNode *node, Thread *current_thread = Thread::get_current_thread()) const;
+
+  void add_stashed(PandaNode *child_node, int sort = 0, Thread *current_thread = Thread::get_current_thread());
+  void remove_stashed(int child_index, Thread *current_thread = Thread::get_current_thread());
+
+  void remove_all_children(Thread *current_thread = Thread::get_current_thread());
+  void steal_children(PandaNode *other, Thread *current_thread = Thread::get_current_thread());
+  void copy_children(PandaNode *other, Thread *current_thread = Thread::get_current_thread());
 
   void set_attrib(const RenderAttrib *attrib, int override = 0);
   INLINE const RenderAttrib *get_attrib(TypeHandle type) const;
@@ -157,23 +165,23 @@ PUBLISHED:
   INLINE bool has_effect(TypeHandle type) const;
   void clear_effect(TypeHandle type);
 
-  void set_state(const RenderState *state);
-  INLINE const RenderState *get_state() const;
-  INLINE void clear_state();
+  void set_state(const RenderState *state, Thread *current_thread = Thread::get_current_thread());
+  INLINE const RenderState *get_state(Thread *current_thread = Thread::get_current_thread()) const;
+  INLINE void clear_state(Thread *current_thread = Thread::get_current_thread());
 
   void set_effects(const RenderEffects *effects);
   INLINE const RenderEffects *get_effects() const;
   INLINE void clear_effects();
 
-  void set_transform(const TransformState *transform);
-  INLINE const TransformState *get_transform() const;
-  INLINE void clear_transform();
+  void set_transform(const TransformState *transform, Thread *current_thread = Thread::get_current_thread());
+  INLINE const TransformState *get_transform(Thread *current_thread = Thread::get_current_thread()) const;
+  INLINE void clear_transform(Thread *current_thread = Thread::get_current_thread());
 
-  void set_prev_transform(const TransformState *transform);
-  INLINE const TransformState *get_prev_transform() const;
-  void reset_prev_transform();
+  void set_prev_transform(const TransformState *transform, Thread *current_thread = Thread::get_current_thread());
+  INLINE const TransformState *get_prev_transform(Thread *current_thread = Thread::get_current_thread()) const;
+  void reset_prev_transform(Thread *current_thread = Thread::get_current_thread());
   INLINE bool has_dirty_prev_transform() const;
-  static void reset_all_prev_transform();
+  static void reset_all_prev_transform(Thread *current_thread = Thread::get_current_thread());
 
   void set_tag(const string &key, const string &value);
   INLINE string get_tag(const string &key) const;
@@ -233,7 +241,7 @@ PUBLISHED:
   CPT(BoundingVolume) get_bounds() const;
   INLINE CPT(BoundingVolume) get_internal_bounds() const;
 
-  void mark_bounds_stale() const;
+  void mark_bounds_stale(Thread *current_thread = Thread::get_current_thread()) const;
 
   INLINE void set_final(bool flag);
   INLINE bool is_final() const;
@@ -243,17 +251,17 @@ PUBLISHED:
   virtual Light *as_light();
 
 protected:
-  INLINE CPT(BoundingVolume) get_user_bounds(int pipeline_stage) const;
-  CPT(BoundingVolume) get_internal_bounds(int pipeline_stage) const;
+  INLINE CPT(BoundingVolume) get_user_bounds(int pipeline_stage, Thread *current_thread) const;
+  CPT(BoundingVolume) get_internal_bounds(int pipeline_stage, Thread *current_thread) const;
   void set_internal_bounds(const BoundingVolume *volume);
 
-  INLINE void mark_bounds_stale(int pipeline_stage) const;
-  void force_bounds_stale();
-  void force_bounds_stale(int pipeline_stage);
-  void mark_internal_bounds_stale();
-  INLINE void mark_internal_bounds_stale(int pipeline_stage);
+  INLINE void mark_bounds_stale(int pipeline_stage, Thread *current_thread) const;
+  void force_bounds_stale(Thread *current_thread = Thread::get_current_thread());
+  void force_bounds_stale(int pipeline_stage, Thread *current_thread);
+  void mark_internal_bounds_stale(Thread *current_thread = Thread::get_current_thread());
+  INLINE void mark_internal_bounds_stale(int pipeline_stage, Thread *current_thread);
 
-  virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage) const;
+  virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage, Thread *current_thread) const;
   virtual void parents_changed();
   virtual void children_changed();
   virtual void transform_changed();
@@ -261,8 +269,10 @@ protected:
   virtual void draw_mask_changed();
 
   typedef pmap<PandaNode *, PandaNode *> InstanceMap;
-  virtual PT(PandaNode) r_copy_subgraph(InstanceMap &inst_map) const;
-  virtual void r_copy_children(const PandaNode *from, InstanceMap &inst_map);
+  virtual PT(PandaNode) r_copy_subgraph(InstanceMap &inst_map,
+                                        Thread *current_thread) const;
+  virtual void r_copy_children(const PandaNode *from, InstanceMap &inst_map,
+                               Thread *current_thread);
 
 private:
   class CDataLight;
@@ -273,39 +283,40 @@ private:
   INLINE int do_find_parent(PandaNode *node, const CDataLinks *cdata) const;
   int do_find_child(PandaNode *node, const CDataLinks *cdata) const;
   int do_find_stashed(PandaNode *node, const CDataLinks *cdata) const;
-  bool stage_remove_child(PandaNode *child_node, int pipeline_stage);
+  bool stage_remove_child(PandaNode *child_node, int pipeline_stage,
+                          Thread *current_thread);
   bool stage_replace_child(PandaNode *orig_child, PandaNode *new_child,
-                           int pipeline_stage);
+                           int pipeline_stage, Thread *current_thread);
 
   // parent-child manipulation for NodePath support.  Don't try to
   // call these directly.
   static PT(NodePathComponent) attach(NodePathComponent *parent, 
 				      PandaNode *child, int sort,
-				      int pipeline_stage);
-  static void detach(NodePathComponent *child, int pipeline_stage);
-  static void detach_one_stage(NodePathComponent *child, int pipeline_stage);
+				      int pipeline_stage, Thread *current_thread);
+  static void detach(NodePathComponent *child, int pipeline_stage, Thread *current_thread);
+  static void detach_one_stage(NodePathComponent *child, int pipeline_stage, Thread *current_thread);
   static bool reparent(NodePathComponent *new_parent,
                        NodePathComponent *child, int sort, bool as_stashed,
-		       int pipeline_stage);
+		       int pipeline_stage, Thread *current_thread);
   static bool reparent_one_stage(NodePathComponent *new_parent,
 				 NodePathComponent *child, int sort, 
-				 bool as_stashed, int pipeline_stage);
+				 bool as_stashed, int pipeline_stage, Thread *current_thread);
   static PT(NodePathComponent) get_component(NodePathComponent *parent,
 					     PandaNode *child,
-					     int pipeline_stage);
+					     int pipeline_stage, Thread *current_thread);
   static PT(NodePathComponent) get_top_component(PandaNode *child, bool force,
-						 int pipeline_stage);
+						 int pipeline_stage, Thread *current_thread);
   PT(NodePathComponent) get_generic_component(bool accept_ambiguity,
-					      int pipeline_stage);
+					      int pipeline_stage, Thread *current_thread);
   PT(NodePathComponent) r_get_generic_component(bool accept_ambiguity, 
 						bool &ambiguity_detected,
-						int pipeline_stage);
+						int pipeline_stage, Thread *current_thread);
   void delete_component(NodePathComponent *component);
   static void sever_connection(PandaNode *parent_node, PandaNode *child_node,
-                               int pipeline_stage);
+                               int pipeline_stage, Thread *current_thread);
   static void new_connection(PandaNode *parent_node, PandaNode *child_node,
-                             int pipeline_stage);
-  void fix_path_lengths(int pipeline_stage);
+                             int pipeline_stage, Thread *current_thread);
+  void fix_path_lengths(int pipeline_stage, Thread *current_thread);
   void r_list_descendants(ostream &out, int indent_level) const;
 
   INLINE void set_dirty_prev_transform();
@@ -561,8 +572,8 @@ private:
   typedef CycleDataStageReader<CDataLinks> CDLinksStageReader;
   typedef CycleDataStageWriter<CDataLinks> CDLinksStageWriter;
 
-  CDBoundsStageWriter update_bounds(int pipeline_stage, 
-				    CDBoundsStageReader &cdata);
+  CDBoundsStageWriter update_bounds(int pipeline_stage,
+                                    CDBoundsStageReader &cdata);
 
   static DrawMask _overall_bit;
 
@@ -578,12 +589,14 @@ public:
   // pass.
   class EXPCL_PANDA Children {
   public:
-    INLINE Children(const CDLinksReader &cdata);
+    INLINE Children();
+    INLINE Children(const CDataLinks *cdata);
     INLINE Children(const Children &copy);
     INLINE void operator = (const Children &copy);
 
     INLINE int get_num_children() const;
     INLINE PandaNode *get_child(int n) const;
+    INLINE int get_child_sort(int n) const;
 
   private:
     CPT(Down) _down;
@@ -592,12 +605,14 @@ public:
   // Similarly for stashed children.
   class EXPCL_PANDA Stashed {
   public:
-    INLINE Stashed(const CDLinksReader &cdata);
+    INLINE Stashed();
+    INLINE Stashed(const CDataLinks *cdata);
     INLINE Stashed(const Stashed &copy);
     INLINE void operator = (const Stashed &copy);
 
     INLINE int get_num_stashed() const;
     INLINE PandaNode *get_stashed(int n) const;
+    INLINE int get_stashed_sort(int n) const;
 
   private:
     CPT(Down) _stashed;
@@ -606,7 +621,8 @@ public:
   // This class is returned from get_parents().
   class EXPCL_PANDA Parents {
   public:
-    INLINE Parents(const CDLinksReader &cdata);
+    INLINE Parents();
+    INLINE Parents(const CDataLinks *cdata);
     INLINE Parents(const Parents &copy);
     INLINE void operator = (const Parents &copy);
 

+ 2 - 2
panda/src/pgraph/planeNode.cxx

@@ -209,8 +209,8 @@ is_renderable() const {
 //               something internally.
 ////////////////////////////////////////////////////////////////////
 PT(BoundingVolume) PlaneNode::
-compute_internal_bounds(int pipeline_stage) const {
-  CDStageReader cdata(_cycler, pipeline_stage);
+compute_internal_bounds(int pipeline_stage, Thread *current_thread) const {
+  CDStageReader cdata(_cycler, pipeline_stage, current_thread);
   return new BoundingPlane(cdata->_plane);
 }
 

+ 1 - 1
panda/src/pgraph/planeNode.h

@@ -69,7 +69,7 @@ public:
   INLINE static UpdateSeq get_sort_seq();
 
 protected:
-  virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage) const;
+  virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage, Thread *current_thread) const;
   PT(Geom) get_viz(CullTraverser *trav, CullTraverserData &data);
   
 private:

+ 2 - 2
panda/src/pgraph/portalNode.cxx

@@ -389,9 +389,9 @@ draw() const {
 //               thing.
 ////////////////////////////////////////////////////////////////////
 PT(BoundingVolume) PortalNode::
-compute_internal_bounds(int pipeline_stage) const {
+compute_internal_bounds(int pipeline_stage, Thread *current_thread) const {
   // First, get ourselves a fresh, empty bounding volume.
-  PT(BoundingVolume) bound = PandaNode::compute_internal_bounds(pipeline_stage);
+  PT(BoundingVolume) bound = PandaNode::compute_internal_bounds(pipeline_stage, current_thread);
   nassertr(bound != (BoundingVolume *)NULL, bound);
 
   GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, bound);

+ 1 - 1
panda/src/pgraph/portalNode.h

@@ -98,7 +98,7 @@ PUBLISHED:
   //  void draw () const;
 
 protected:
-  virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage) const;
+  virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage, Thread *current_thread) const;
 
 private:
   CPT(RenderState) get_last_pos_state();

+ 8 - 6
panda/src/pgraph/workingNodePath.cxx

@@ -50,8 +50,9 @@ is_valid() const {
 int WorkingNodePath::
 get_num_nodes() const {
   if (_next == (WorkingNodePath *)NULL) {
-    int pipeline_stage = Thread::get_current_pipeline_stage();
-    return _start->get_length(pipeline_stage);
+    Thread *current_thread = Thread::get_current_thread();
+    int pipeline_stage = current_thread->get_pipeline_stage();
+    return _start->get_length(pipeline_stage, current_thread);
   }
 
   return _next->get_num_nodes() + 1;
@@ -111,15 +112,16 @@ r_get_node_path() const {
   PT(NodePathComponent) comp = _next->r_get_node_path();
   nassertr(comp != (NodePathComponent *)NULL, NULL);
 
-  int pipeline_stage = Thread::get_current_pipeline_stage();
-  PT(NodePathComponent) result = PandaNode::get_component(comp, _node,
-							  pipeline_stage);
+  Thread *current_thread = Thread::get_current_thread();
+  int pipeline_stage = current_thread->get_pipeline_stage();
+  PT(NodePathComponent) result = 
+    PandaNode::get_component(comp, _node, pipeline_stage, current_thread);
   if (result == (NodePathComponent *)NULL) {
     // This means we found a disconnected chain in the
     // WorkingNodePath's ancestry: the node above this node isn't
     // connected.  In this case, don't attempt to go higher; just
     // truncate the NodePath at the bottom of the disconnect.
-    return PandaNode::get_top_component(_node, true, pipeline_stage);
+    return PandaNode::get_top_component(_node, true, pipeline_stage, current_thread);
   }
 
   return result;

Some files were not shown because too many files changed in this diff