Browse Source

Further optimizations to the cull pipeline.
The only transform still stored in CullableObject is internal transform.

NB: I haven't tested my PipeOcclusionCullTraverser changes. Please contact me if you encounter problems with it.

rdb 11 years ago
parent
commit
0ad0d4ec33
38 changed files with 436 additions and 403 deletions
  1. 21 25
      panda/src/collide/collisionVisualizer.cxx
  2. 4 4
      panda/src/cull/cullBinBackToFront.cxx
  3. 4 4
      panda/src/cull/cullBinFrontToBack.cxx
  4. 2 2
      panda/src/cull/cullBinStateSorted.I
  5. 3 0
      panda/src/display/graphicsEngine.cxx
  6. 1 1
      panda/src/display/graphicsStateGuardian.I
  7. 5 5
      panda/src/display/graphicsStateGuardian.cxx
  8. 13 0
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  9. 2 0
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  10. 69 53
      panda/src/grutil/pipeOcclusionCullTraverser.cxx
  11. 10 9
      panda/src/grutil/pipeOcclusionCullTraverser.h
  12. 3 3
      panda/src/gsgbase/graphicsStateGuardianBase.h
  13. 58 66
      panda/src/parametrics/ropeNode.cxx
  14. 18 20
      panda/src/parametrics/sheetNode.cxx
  15. 2 2
      panda/src/pgraph/cullBin.cxx
  16. 3 4
      panda/src/pgraph/cullHandler.cxx
  17. 21 22
      panda/src/pgraph/cullPlanes.cxx
  18. 8 13
      panda/src/pgraph/cullTraverser.cxx
  19. 3 6
      panda/src/pgraph/cullTraverser.h
  20. 22 0
      panda/src/pgraph/cullTraverserData.I
  21. 0 11
      panda/src/pgraph/cullTraverserData.cxx
  22. 8 5
      panda/src/pgraph/cullTraverserData.h
  23. 0 30
      panda/src/pgraph/cullableObject.I
  24. 19 17
      panda/src/pgraph/cullableObject.cxx
  25. 0 8
      panda/src/pgraph/cullableObject.h
  26. 2 5
      panda/src/pgraph/geomNode.cxx
  27. 1 0
      panda/src/pgraph/geomNode.h
  28. 27 0
      panda/src/pgraph/nodePath.I
  29. 5 0
      panda/src/pgraph/nodePath.h
  30. 6 10
      panda/src/pgraph/occluderNode.cxx
  31. 6 8
      panda/src/pgraph/planeNode.cxx
  32. 25 0
      panda/src/pgraph/sceneSetup.I
  33. 4 0
      panda/src/pgraph/sceneSetup.h
  34. 3 5
      panda/src/pgraphnodes/callbackNode.cxx
  35. 2 4
      panda/src/pgraphnodes/computeNode.cxx
  36. 2 4
      panda/src/pgraphnodes/nodeCullCallbackData.cxx
  37. 4 5
      panda/src/rocket/rocketRenderInterface.cxx
  38. 50 52
      panda/src/speedtree/speedTreeNode.cxx

+ 21 - 25
panda/src/collide/collisionVisualizer.cxx

@@ -122,14 +122,14 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
     const VizInfo &viz_info = (*di).second;
 
     CullTraverserData xform_data(data);
-    
+
     // We don't want to inherit the transform from above!  We ignore
     // whatever transforms were above the CollisionVisualizer node; it
     // always renders its objects according to their appropriate net
     // transform.
     xform_data._net_transform = TransformState::make_identity();
     xform_data._view_frustum = trav->get_view_frustum();
-    xform_data.apply_transform_and_state(trav, net_transform, 
+    xform_data.apply_transform_and_state(trav, net_transform,
                                          RenderState::make_empty(),
                                          RenderEffects::make_empty(),
                                          ClipPlaneAttrib::make());
@@ -148,7 +148,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
       PT(PandaNode) node = solid->get_viz(trav, xform_data, !was_detected);
       if (node != (PandaNode *)NULL) {
         CullTraverserData next_data(xform_data, node);
-        
+
         // We don't want to inherit the render state from above for
         // these guys.
         next_data._state = get_viz_state();
@@ -161,16 +161,16 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
       CPT(RenderState) empty_state = RenderState::make_empty();
       CPT(RenderState) point_state = RenderState::make(RenderModeAttrib::make(RenderModeAttrib::M_unchanged, 1.0f, false));
 
-      PT(GeomVertexArrayFormat) point_array_format = 
+      PT(GeomVertexArrayFormat) point_array_format =
         new GeomVertexArrayFormat(InternalName::get_vertex(), 3,
                                   Geom::NT_stdfloat, Geom::C_point,
                                   InternalName::get_color(), 1,
                                   Geom::NT_packed_dabc, Geom::C_color,
-                                  InternalName::get_size(), 1, 
+                                  InternalName::get_size(), 1,
                                   Geom::NT_stdfloat, Geom::C_other);
-      CPT(GeomVertexFormat) point_format = 
+      CPT(GeomVertexFormat) point_format =
         GeomVertexFormat::register_format(point_array_format);
-        
+
       Points::const_iterator pi;
       for (pi = viz_info._points.begin(); pi != viz_info._points.end(); ++pi) {
         const CollisionPoint &point = (*pi);
@@ -178,9 +178,9 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
         // Draw a small red point at the surface point, and a smaller
         // white point at the interior point.
         {
-          PT(GeomVertexData) point_vdata = 
+          PT(GeomVertexData) point_vdata =
             new GeomVertexData("viz", point_format, Geom::UH_stream);
-          
+
           PT(GeomPoints) points = new GeomPoints(Geom::UH_stream);
 
           GeomVertexWriter vertex(point_vdata, InternalName::get_vertex());
@@ -203,19 +203,17 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
 
           PT(Geom) geom = new Geom(point_vdata);
           geom->add_primitive(points);
-            
-          CullableObject *object = 
-            new CullableObject(geom, point_state, 
-                               xform_data.get_net_transform(trav),
-                               xform_data.get_modelview_transform(trav),
-                               trav->get_scene());
-          
+
+          CullableObject *object =
+            new CullableObject(geom, point_state,
+                               xform_data.get_internal_transform(trav));
+
           trav->get_cull_handler()->record_object(object, trav);
         }
 
         // Draw the normal vector at the surface point.
         if (!point._surface_normal.almost_equal(LVector3::zero())) {
-          PT(GeomVertexData) line_vdata = 
+          PT(GeomVertexData) line_vdata =
             new GeomVertexData("viz", GeomVertexFormat::get_v3cp(),
                                Geom::UH_stream);
 
@@ -225,7 +223,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
           GeomVertexWriter color(line_vdata, InternalName::get_color());
 
           vertex.add_data3(point._surface_point);
-          vertex.add_data3(point._surface_point + 
+          vertex.add_data3(point._surface_point +
                             point._surface_normal * _normal_scale);
           color.add_data4(1.0f, 0.0f, 0.0f, 1.0f);
           color.add_data4(1.0f, 1.0f, 1.0f, 1.0f);
@@ -234,13 +232,11 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
 
           PT(Geom) geom = new Geom(line_vdata);
           geom->add_primitive(lines);
-          
-          CullableObject *object = 
-            new CullableObject(geom, empty_state, 
-                               xform_data.get_net_transform(trav),
-                               xform_data.get_modelview_transform(trav),
-                               trav->get_scene());
-          
+
+          CullableObject *object =
+            new CullableObject(geom, empty_state,
+                               xform_data.get_internal_transform(trav));
+
           trav->get_cull_handler()->record_object(object, trav);
         }
       }

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

@@ -66,11 +66,11 @@ add_object(CullableObject *object, Thread *current_thread) {
 
   const GeometricBoundingVolume *gbv;
   DCAST_INTO_V(gbv, volume);
-  
+
   LPoint3 center = gbv->get_approx_center();
-  nassertv(object->_modelview_transform != (const TransformState *)NULL);
-  center = center * object->_modelview_transform->get_mat();
-  
+  nassertv(object->_internal_transform != (const TransformState *)NULL);
+  center = center * object->_internal_transform->get_mat();
+
   PN_stdfloat distance = _gsg->compute_distance_to(center);
   _objects.push_back(ObjectData(object, distance));
 }

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

@@ -66,11 +66,11 @@ add_object(CullableObject *object, Thread *current_thread) {
 
   const GeometricBoundingVolume *gbv;
   DCAST_INTO_V(gbv, volume);
-  
+
   LPoint3 center = gbv->get_approx_center();
-  nassertv(object->_modelview_transform != (const TransformState *)NULL);
-  center = center * object->_modelview_transform->get_mat();
-  
+  nassertv(object->_internal_transform != (const TransformState *)NULL);
+  center = center * object->_internal_transform->get_mat();
+
   PN_stdfloat distance = _gsg->compute_distance_to(center);
   _objects.push_back(ObjectData(object, distance));
 }

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

@@ -47,8 +47,8 @@ INLINE bool CullBinStateSorted::ObjectData::
 operator < (const ObjectData &other) const {
   // First group objects by transform, since transform changes are
   // supposed to be expensive.
-  if (_object->_modelview_transform != other._object->_modelview_transform) {
-    return _object->_modelview_transform < other._object->_modelview_transform;
+  if (_object->_internal_transform != other._object->_internal_transform) {
+    return _object->_internal_transform < other._object->_internal_transform;
   }
 
   // Then group by other state changes, in approximate order from

+ 3 - 0
panda/src/display/graphicsEngine.cxx

@@ -1994,6 +1994,9 @@ setup_scene(GraphicsStateGuardian *gsg, DisplayRegionPipelineReader *dr) {
   CPT(TransformState) cs_transform = gsg->get_cs_transform_for(lens->get_coordinate_system());
   scene_setup->set_cs_transform(cs_transform);
 
+  CPT(TransformState) cs_world_transform = cs_transform->compose(world_transform);
+  scene_setup->set_cs_world_transform(cs_world_transform);
+
   return scene_setup;
 }
 

+ 1 - 1
panda/src/display/graphicsStateGuardian.I

@@ -204,7 +204,7 @@ set_loader(Loader *loader) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::get_loader
-//       Access: Public, Virtual
+//       Access: Public
 //  Description: Returns the Loader object that will be used by this
 //               GSG to load textures when necessary, if
 //               get_incomplete_render() is true.

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

@@ -878,14 +878,14 @@ make_geom_munger(const RenderState *state, Thread *current_thread) {
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::compute_distance_to
 //       Access: Public, Virtual
-//  Description: This function may only be called during a render
-//               traversal; it will compute the distance to the
+//  Description: This function will compute the distance to the
 //               indicated point, assumed to be in eye coordinates,
-//               from the camera plane.
+//               from the camera plane.  The point is assumed to be
+//               in the GSG's internal coordinate system.
 ////////////////////////////////////////////////////////////////////
 PN_stdfloat GraphicsStateGuardian::
 compute_distance_to(const LPoint3 &point) const {
-  switch (_coordinate_system) {
+  switch (_internal_coordinate_system) {
   case CS_zup_right:
     return point[1];
 
@@ -901,7 +901,7 @@ compute_distance_to(const LPoint3 &point) const {
   default:
     gsg_cat.error()
       << "Invalid coordinate system in compute_distance_to: "
-      << (int)_coordinate_system << "\n";
+      << (int)_internal_coordinate_system << "\n";
     return 0.0f;
   }
 }

+ 13 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -5157,6 +5157,19 @@ make_geom_munger(const RenderState *state, Thread *current_thread) {
   return GeomMunger::register_munger(munger, current_thread);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::compute_distance_to
+//       Access: Public, Virtual
+//  Description: This function will compute the distance to the
+//               indicated point, assumed to be in eye coordinates,
+//               from the camera plane.  The point is assumed to be
+//               in the GSG's internal coordinate system.
+////////////////////////////////////////////////////////////////////
+PN_stdfloat GLGraphicsStateGuardian::
+compute_distance_to(const LPoint3 &point) const {
+  return -point[2];
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::framebuffer_copy_to_texture
 //       Access: Public, Virtual

+ 2 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -326,6 +326,8 @@ public:
   virtual PT(GeomMunger) make_geom_munger(const RenderState *state,
                                           Thread *current_thread);
 
+  virtual PN_stdfloat compute_distance_to(const LPoint3 &point) const;
+
   virtual void clear(DrawableRegion *region);
 
   virtual bool framebuffer_copy_to_texture

+ 69 - 53
panda/src/grutil/pipeOcclusionCullTraverser.cxx

@@ -76,7 +76,7 @@ static ConfigVariableInt occlusion_depth_bits
 ////////////////////////////////////////////////////////////////////
 //     Function: PipeOcclusionCullTraverser::Constructor
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 PipeOcclusionCullTraverser::
 PipeOcclusionCullTraverser(GraphicsOutput *host) {
@@ -103,7 +103,7 @@ PipeOcclusionCullTraverser(GraphicsOutput *host) {
     win_prop.set_size(occlusion_size[0], occlusion_size[1]);
   }
 
-  _buffer = engine->make_output(pipe, "occlusion", 0, fb_prop, win_prop, 
+  _buffer = engine->make_output(pipe, "occlusion", 0, fb_prop, win_prop,
                                 GraphicsPipe::BF_refuse_window,
                                 gsg, host->get_host());
   nassertv(_buffer != (GraphicsOutput *)NULL);
@@ -125,7 +125,7 @@ PipeOcclusionCullTraverser(GraphicsOutput *host) {
 ////////////////////////////////////////////////////////////////////
 //     Function: PipeOcclusionCullTraverser::Copy Constructor
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 PipeOcclusionCullTraverser::
 PipeOcclusionCullTraverser(const PipeOcclusionCullTraverser &copy) :
@@ -137,7 +137,7 @@ PipeOcclusionCullTraverser(const PipeOcclusionCullTraverser &copy) :
 ////////////////////////////////////////////////////////////////////
 //     Function: PipeOcclusionCullTraverser::set_scene
 //       Access: Published, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 void PipeOcclusionCullTraverser::
 set_scene(SceneSetup *scene_setup, GraphicsStateGuardianBase *gsgbase,
@@ -154,7 +154,7 @@ set_scene(SceneSetup *scene_setup, GraphicsStateGuardianBase *gsgbase,
 
   Thread *current_thread = get_current_thread();
   if (!_buffer->begin_frame(GraphicsOutput::FM_render, current_thread)) {
-    cerr << "begin_frame failed\n";
+    grutil_cat.error() << "begin_frame failed\n";
     return;
   }
   _buffer->clear(current_thread);
@@ -166,7 +166,7 @@ set_scene(SceneSetup *scene_setup, GraphicsStateGuardianBase *gsgbase,
 
   _scene = new SceneSetup(*scene_setup);
   _scene->set_display_region(_display_region);
-  _scene->set_viewport_size(_display_region->get_pixel_width(), 
+  _scene->set_viewport_size(_display_region->get_pixel_width(),
                             _display_region->get_pixel_height());
 
   if (_scene->get_cull_center() != _scene->get_camera_path()) {
@@ -177,13 +177,22 @@ set_scene(SceneSetup *scene_setup, GraphicsStateGuardianBase *gsgbase,
     NodePath scene_parent = _scene->get_scene_root().get_parent(current_thread);
     CPT(TransformState) camera_transform = cull_center.get_transform(scene_parent, current_thread);
     CPT(TransformState) world_transform = scene_parent.get_transform(cull_center, current_thread);
+    CPT(TransformState) cs_world_transform = _scene->get_cs_transform()->compose(world_transform);
     _scene->set_camera_transform(camera_transform);
     _scene->set_world_transform(world_transform);
+    _scene->set_cs_world_transform(cs_world_transform);
+
+    // We use this to recover the original net_transform.
+    _inv_cs_world_transform = cs_world_transform->get_inverse();
+  } else {
+    _inv_cs_world_transform = _scene->get_cs_world_transform()->get_inverse();
   }
-    
+
+  nassertv(_scene->get_cs_transform() == scene_setup->get_cs_transform());
+
   gsg->set_scene(_scene);
   if (!gsg->begin_scene()) {
-    cerr << "begin_scene failed\n";
+    grutil_cat.error() << "begin_scene failed\n";
     return;
   }
 
@@ -202,7 +211,7 @@ set_scene(SceneSetup *scene_setup, GraphicsStateGuardianBase *gsgbase,
 
   _current_query = NULL;
   _next_query = NULL;
-  
+
   // Begin by rendering all the occluders into our internal scene.
   PStatTimer timer2(_draw_occlusion_pcollector);
   _internal_trav->traverse(_scene->get_scene_root());
@@ -299,7 +308,7 @@ get_texture() {
 ////////////////////////////////////////////////////////////////////
 //     Function: PipeOcclusionCullTraverser::is_in_view
 //       Access: Protected, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 bool PipeOcclusionCullTraverser::
 is_in_view(CullTraverserData &data) {
@@ -335,12 +344,12 @@ is_in_view(CullTraverserData &data) {
 
     CPT(BoundingVolume) vol = node_reader->get_bounds();
     CPT(TransformState) net_transform = data.get_net_transform(this);
-    CPT(TransformState) modelview_transform;
+    CPT(TransformState) internal_transform;
 
     CPT(Geom) geom;
-    if (get_volume_viz(vol, geom, net_transform, modelview_transform)) {
-      _next_query = 
-        perform_occlusion_test(geom, net_transform, modelview_transform);
+    if (get_volume_viz(vol, geom, net_transform, internal_transform)) {
+      _next_query =
+        perform_occlusion_test(geom, net_transform, internal_transform);
     }
   }
 
@@ -408,12 +417,12 @@ record_object(CullableObject *object, const CullTraverser *traverser) {
   } else {
     // Issue an occlusion test for this object.
     CPT(BoundingVolume) vol = object->_geom->get_bounds(current_thread);
-    CPT(TransformState) net_transform = object->_net_transform;
-    CPT(TransformState) modelview_transform;
+    CPT(TransformState) net_transform = _inv_cs_world_transform->compose(object->_internal_transform);
+    CPT(TransformState) internal_transform;
     CPT(Geom) geom;
-    if (get_volume_viz(vol, geom, net_transform, modelview_transform)) {
-      pobj._query = 
-        perform_occlusion_test(geom, net_transform, modelview_transform);
+    if (get_volume_viz(vol, geom, net_transform, internal_transform)) {
+      pobj._query =
+        perform_occlusion_test(geom, net_transform, internal_transform);
     }
   }
 
@@ -437,7 +446,7 @@ make_sphere() {
   PT(GeomVertexData) vdata = new GeomVertexData
     ("occlusion_sphere", GeomVertexFormat::get_v3(), Geom::UH_static);
   GeomVertexWriter vertex(vdata, InternalName::get_vertex());
-  
+
   PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_stream);
   for (int sl = 0; sl < num_slices; ++sl) {
     PN_stdfloat longitude0 = (PN_stdfloat)sl / (PN_stdfloat)num_slices;
@@ -449,11 +458,11 @@ make_sphere() {
       vertex.add_data3(compute_sphere_point(latitude, longitude1));
     }
     vertex.add_data3(compute_sphere_point(1.0, longitude0));
-    
+
     strip->add_next_vertices(num_stacks * 2);
     strip->close_primitive();
   }
-  
+
   _sphere_geom = new Geom(vdata);
   _sphere_geom->add_primitive(strip);
 }
@@ -462,7 +471,7 @@ make_sphere() {
 //     Function: PipeOcclusionCullTraverser::compute_sphere_point
 //       Access: Private, Static
 //  Description: Returns a point on the surface of the unit sphere.
-//               latitude and longitude range from 0.0 to 1.0.  
+//               latitude and longitude range from 0.0 to 1.0.
 ////////////////////////////////////////////////////////////////////
 LVertex PipeOcclusionCullTraverser::
 compute_sphere_point(PN_stdfloat latitude, PN_stdfloat longitude) {
@@ -487,7 +496,7 @@ make_box() {
   PT(GeomVertexData) vdata = new GeomVertexData
     ("occlusion_box", GeomVertexFormat::get_v3(), Geom::UH_static);
   GeomVertexWriter vertex(vdata, InternalName::get_vertex());
-  
+
   vertex.add_data3(0.0f, 0.0f, 0.0f);
   vertex.add_data3(0.0f, 0.0f, 1.0f);
   vertex.add_data3(0.0f, 1.0f, 0.0f);
@@ -496,7 +505,7 @@ make_box() {
   vertex.add_data3(1.0f, 0.0f, 1.0f);
   vertex.add_data3(1.0f, 1.0f, 0.0f);
   vertex.add_data3(1.0f, 1.0f, 1.0f);
-    
+
   PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static);
   tris->add_vertices(0, 4, 5);
   tris->close_primitive();
@@ -522,7 +531,7 @@ make_box() {
   tris->close_primitive();
   tris->add_vertices(2, 4, 0);
   tris->close_primitive();
-  
+
   _box_geom = new Geom(vdata);
   _box_geom->add_primitive(tris);
 }
@@ -554,14 +563,14 @@ make_solid_test_state() {
 //               transform to the bounding volume.  On exit (when
 //               return value is true), it will be composed with a
 //               suitable local transform to render the bounding
-//               volume properly, and modelview_transform will also be
+//               volume properly, and internal_transform will also be
 //               filled with the appropriate transform.
 ////////////////////////////////////////////////////////////////////
 bool PipeOcclusionCullTraverser::
-get_volume_viz(const BoundingVolume *vol, 
+get_volume_viz(const BoundingVolume *vol,
                CPT(Geom) &geom,  // OUT
                CPT(TransformState) &net_transform, // IN-OUT
-               CPT(TransformState) &modelview_transform  // OUT
+               CPT(TransformState) &internal_transform  // OUT
                ) {
   if (vol->is_infinite() || vol->is_empty()) {
     return false;
@@ -569,13 +578,14 @@ get_volume_viz(const BoundingVolume *vol,
 
   if (vol->is_exact_type(BoundingSphere::get_class_type())) {
     const BoundingSphere *sphere = DCAST(BoundingSphere, vol);
-    CPT(TransformState) local_transform = 
+    CPT(TransformState) local_transform =
       TransformState::make_pos_hpr_scale(sphere->get_center(),
                                          LVecBase3(0, 0, 0),
                                          sphere->get_radius());
     net_transform = net_transform->compose(local_transform);
 
-    modelview_transform = _internal_trav->get_world_transform()->compose(net_transform);
+    CPT(TransformState) modelview_transform =
+      _internal_trav->get_world_transform()->compose(net_transform);
 
     // See if the bounding sphere is clipped by the near plane.  If it
     // is, the occlusion test may fail, so we won't bother performing
@@ -587,19 +597,24 @@ get_volume_viz(const BoundingVolume *vol,
       return false;
     }
 
+    // Construct the internal transform for the internal traverser.
+    internal_transform = _internal_trav->get_scene()->
+      get_cs_transform()->compose(modelview_transform);
+
     // The sphere looks good.
     geom = _sphere_geom;
     return true;
 
   } else if (vol->is_exact_type(BoundingBox::get_class_type())) {
     const BoundingBox *box = DCAST(BoundingBox, vol);
-    CPT(TransformState) local_transform = 
+    CPT(TransformState) local_transform =
       TransformState::make_pos_hpr_scale(box->get_minq(),
                                          LVecBase3(0, 0, 0),
                                          box->get_maxq() - box->get_minq());
     net_transform = net_transform->compose(local_transform);
 
-    modelview_transform = _internal_trav->get_world_transform()->compose(net_transform);
+    CPT(TransformState) modelview_transform =
+      _internal_trav->get_world_transform()->compose(net_transform);
 
     // See if the bounding box is clipped by the near plane.  If it
     // is, the occlusion test may fail, so we won't bother performing
@@ -623,6 +638,10 @@ get_volume_viz(const BoundingVolume *vol,
       }
     }
 
+    // Construct the internal transform for the internal traverser.
+    internal_transform = _internal_trav->get_scene()->
+      get_cs_transform()->compose(modelview_transform);
+
     // The box looks good.
     geom = _box_geom;
     return true;
@@ -640,7 +659,7 @@ get_volume_viz(const BoundingVolume *vol,
 ////////////////////////////////////////////////////////////////////
 PT(OcclusionQueryContext) PipeOcclusionCullTraverser::
 perform_occlusion_test(const Geom *geom, const TransformState *net_transform,
-                       const TransformState *modelview_transform) {
+                       const TransformState *internal_transform) {
   _occlusion_tests_pcollector.add_level(1);
   PStatTimer timer(_test_occlusion_pcollector);
 
@@ -648,9 +667,8 @@ perform_occlusion_test(const Geom *geom, const TransformState *net_transform,
 
   gsg->begin_occlusion_query();
 
-  CullableObject *viz = 
-    new CullableObject(geom, _solid_test_state,
-                       net_transform, modelview_transform, get_scene());
+  CullableObject *viz =
+    new CullableObject(geom, _solid_test_state, internal_transform);
 
   static ConfigVariableBool test_occlude("test-occlude", false);
   if (test_occlude) {
@@ -658,16 +676,16 @@ perform_occlusion_test(const Geom *geom, const TransformState *net_transform,
   } else {
     _internal_cull_handler->record_object(viz, _internal_trav);
   }
-  
+
   PT(OcclusionQueryContext) query = gsg->end_occlusion_query();
-    
+
   if (show_occlusion) {
     // Show the results of the occlusion.  To do this, we need to get
     // the results of the query immediately.  This will stall the
     // pipe, but we're rendering a debug effect, so we don't mind too
     // much.
     int num_fragments = query->get_num_fragments();
-    show_results(num_fragments, geom, net_transform, modelview_transform);
+    show_results(num_fragments, geom, net_transform, internal_transform);
   }
 
   return query;
@@ -680,18 +698,18 @@ perform_occlusion_test(const Geom *geom, const TransformState *net_transform,
 //               test for a particular bounding volume.
 ////////////////////////////////////////////////////////////////////
 void PipeOcclusionCullTraverser::
-show_results(int num_fragments, const Geom *geom, 
-             const TransformState *net_transform, 
-             const TransformState *modelview_transform) {
+show_results(int num_fragments, const Geom *geom,
+             const TransformState *net_transform,
+             const TransformState *internal_transform) {
   LColor color;
   if (num_fragments == 0) {
     // Magenta: culled
-    color.set(0.8f, 0.0f, 1.0f, 0.4);
+    color.set(0.8f, 0.0f, 1.0f, 0.4f);
   } else {
     // Yellow: visible
-    color.set(1.0f, 1.0f, 0.5f, 0.4);
+    color.set(1.0f, 1.0f, 0.5f, 0.4f);
   }
-  
+
   CPT(RenderState) state = RenderState::make
     (DepthWriteAttrib::make(DepthWriteAttrib::M_off),
      DepthTestAttrib::make(DepthTestAttrib::M_less),
@@ -700,15 +718,13 @@ show_results(int num_fragments, const Geom *geom,
 
   GraphicsStateGuardian *gsg = _buffer->get_gsg();
 
-  CullableObject *internal_viz = 
-    new CullableObject(geom, state,
-                       net_transform, modelview_transform, get_scene());
+  CullableObject *internal_viz =
+    new CullableObject(geom, state, internal_transform);
   _internal_cull_handler->record_object(internal_viz, _internal_trav);
 
   // Also render the viz in the main scene.
-  modelview_transform = get_world_transform()->compose(net_transform);
-  CullableObject *main_viz = 
-    new CullableObject(geom, state,
-                       net_transform, modelview_transform, get_scene());
+  internal_transform = get_scene()->get_cs_world_transform()->compose(net_transform);
+  CullableObject *main_viz =
+    new CullableObject(geom, state, internal_transform);
   _true_cull_handler->record_object(main_viz, this);
 }

+ 10 - 9
panda/src/grutil/pipeOcclusionCullTraverser.h

@@ -75,19 +75,19 @@ private:
 
   void make_solid_test_state();
 
-  bool get_volume_viz(const BoundingVolume *vol, 
+  bool get_volume_viz(const BoundingVolume *vol,
                       CPT(Geom) &geom,  // OUT
                       CPT(TransformState) &net_transform, // IN-OUT
-                      CPT(TransformState) &modelview_transform  // OUT
+                      CPT(TransformState) &internal_transform  // OUT
                       );
-  PT(OcclusionQueryContext) 
-    perform_occlusion_test(const Geom *geom, 
+  PT(OcclusionQueryContext)
+    perform_occlusion_test(const Geom *geom,
                            const TransformState *net_transform,
-                           const TransformState *modelview_transform);
+                           const TransformState *internal_transform);
 
-  void show_results(int num_fragments, const Geom *geom, 
-                    const TransformState *net_transform, 
-                    const TransformState *modelview_transform);
+  void show_results(int num_fragments, const Geom *geom,
+                    const TransformState *net_transform,
+                    const TransformState *internal_transform);
 private:
   bool _live;
 
@@ -98,6 +98,7 @@ private:
 
   PT(SceneSetup) _scene;
   PT(CullTraverser) _internal_trav;
+  CPT(TransformState) _inv_cs_world_transform;
 
   CullHandler *_internal_cull_handler;
   CullHandler *_true_cull_handler;
@@ -157,4 +158,4 @@ private:
 #endif
 
 
-  
+

+ 3 - 3
panda/src/gsgbase/graphicsStateGuardianBase.h

@@ -198,9 +198,9 @@ public:
   // inconvenient to declare each of those types to be friends of this
   // class.
 
-  virtual bool begin_draw_primitives(const GeomPipelineReader *geom_reader, 
+  virtual bool begin_draw_primitives(const GeomPipelineReader *geom_reader,
                                      const GeomMunger *munger,
-                                     const GeomVertexDataPipelineReader *data_reader, 
+                                     const GeomVertexDataPipelineReader *data_reader,
                                      bool force)=0;
   virtual bool draw_triangles(const GeomPrimitivePipelineReader *reader, bool force)=0;
   virtual bool draw_tristrips(const GeomPrimitivePipelineReader *reader, bool force)=0;
@@ -218,7 +218,7 @@ public:
 
   virtual CoordinateSystem get_internal_coordinate_system() const=0;
 
-  virtual void bind_light(PointLight *light_obj, const NodePath &light, 
+  virtual void bind_light(PointLight *light_obj, const NodePath &light,
                           int light_id) { }
   virtual void bind_light(DirectionalLight *light_obj, const NodePath &light,
                           int light_id) { }

+ 58 - 66
panda/src/parametrics/ropeNode.cxx

@@ -167,15 +167,15 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
         case RM_thread:
           render_thread(trav, data, result);
           break;
-          
+
         case RM_tape:
           render_tape(trav, data, result);
           break;
-          
+
         case RM_billboard:
           render_billboard(trav, data, result);
           break;
-          
+
         case RM_tube:
           render_tube(trav, data, result);
           break;
@@ -183,7 +183,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
       }
     }
   }
-  
+
   return true;
 }
 
@@ -205,7 +205,7 @@ is_renderable() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: RopeNode::output
 //       Access: Public, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 void RopeNode::
 output(ostream &out) const {
@@ -221,7 +221,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 //     Function: RopeNode::write
 //       Access: Public, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 void RopeNode::
 write(ostream &out, int indent_level) const {
@@ -258,8 +258,8 @@ compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
                         int &internal_vertices,
                         int pipeline_stage,
                         Thread *current_thread) const {
-  PT(BoundingVolume) bounds = 
-    do_recompute_bounds(NodePath((PandaNode *)this), pipeline_stage, 
+  PT(BoundingVolume) bounds =
+    do_recompute_bounds(NodePath((PandaNode *)this), pipeline_stage,
                         current_thread);
 
   internal_bounds = bounds;
@@ -304,7 +304,7 @@ 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, 
+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
@@ -312,7 +312,7 @@ do_recompute_bounds(const NodePath &rel_to, int pipeline_stage,
 
   // First, get ourselves a fresh, empty bounding volume.
   PT(BoundingVolume) bound = new BoundingSphere;
-  
+
   NurbsCurveEvaluator *curve = get_curve();
   if (curve != (NurbsCurveEvaluator *)NULL) {
     NurbsCurveEvaluator::Vert3Array verts;
@@ -326,7 +326,7 @@ do_recompute_bounds(const NodePath &rel_to, int pipeline_stage,
         (*vi) = LPoint3(*vi) * mat;
       }
     }
-    
+
     GeometricBoundingVolume *gbv;
     DCAST_INTO_R(gbv, bound, bound);
     gbv->around(&verts[0], &verts[0] + verts.size());
@@ -349,7 +349,7 @@ do_recompute_bounds(const NodePath &rel_to, int pipeline_stage,
 //               per-vertex thickness.
 ////////////////////////////////////////////////////////////////////
 void RopeNode::
-render_thread(CullTraverser *trav, CullTraverserData &data, 
+render_thread(CullTraverser *trav, CullTraverserData &data,
               NurbsCurveResult *result) const {
   CurveSegments curve_segments;
   int num_curve_verts = get_connected_segments(curve_segments, result);
@@ -370,21 +370,19 @@ render_thread(CullTraverser *trav, CullTraverserData &data,
     lines->add_vertex(vi + 1);
     lines->close_primitive();
   }
-  
+
   PT(Geom) geom = new Geom(vdata);
   geom->add_primitive(lines);
-  
+
   CPT(RenderAttrib) thick = RenderModeAttrib::make(RenderModeAttrib::M_unchanged, get_thickness());
   CPT(RenderState) state = data._state->add_attrib(thick);
   if (get_use_vertex_color()) {
     state = state->add_attrib(ColorAttrib::make_vertex());
   }
-  
-  CullableObject *object = 
+
+  CullableObject *object =
     new CullableObject(geom, state,
-                       data.get_net_transform(trav),
-                       data.get_modelview_transform(trav),
-                       trav->get_scene());
+                       data.get_internal_transform(trav));
   trav->get_cull_handler()->record_object(object, trav);
 }
 
@@ -399,7 +397,7 @@ render_thread(CullTraverser *trav, CullTraverserData &data,
 //               determines the width of the triangle strips.
 ////////////////////////////////////////////////////////////////////
 void RopeNode::
-render_tape(CullTraverser *trav, CullTraverserData &data, 
+render_tape(CullTraverser *trav, CullTraverserData &data,
             NurbsCurveResult *result) const {
   CurveSegments curve_segments;
   int num_curve_verts = get_connected_segments(curve_segments, result);
@@ -409,8 +407,8 @@ render_tape(CullTraverser *trav, CullTraverserData &data,
   // either side.
   PT(GeomVertexData) vdata = new GeomVertexData
     ("rope", get_format(false), Geom::UH_stream);
-  
-  compute_billboard_vertices(vdata, -get_tube_up(), 
+
+  compute_billboard_vertices(vdata, -get_tube_up(),
                              curve_segments, num_curve_verts, result);
 
   // Since this will be a nonindexed primitive, no need to pre-reserve
@@ -419,11 +417,11 @@ render_tape(CullTraverser *trav, CullTraverserData &data,
   CurveSegments::const_iterator si;
   for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
     const CurveSegment &segment = (*si);
-    
+
     strip->add_next_vertices(segment.size() * 2);
     strip->close_primitive();
   }
-  
+
   PT(Geom) geom = new Geom(vdata);
   geom->add_primitive(strip);
 
@@ -431,12 +429,10 @@ render_tape(CullTraverser *trav, CullTraverserData &data,
   if (get_use_vertex_color()) {
     state = state->add_attrib(ColorAttrib::make_vertex());
   }
-  
-  CullableObject *object = 
+
+  CullableObject *object =
     new CullableObject(geom, state,
-                       data.get_net_transform(trav),
-                       data.get_modelview_transform(trav),
-                       trav->get_scene());
+                       data.get_internal_transform(trav));
   trav->get_cull_handler()->record_object(object, trav);
 }
 
@@ -451,7 +447,7 @@ render_tape(CullTraverser *trav, CullTraverserData &data,
 //               determines the width of the triangle strips.
 ////////////////////////////////////////////////////////////////////
 void RopeNode::
-render_billboard(CullTraverser *trav, CullTraverserData &data, 
+render_billboard(CullTraverser *trav, CullTraverserData &data,
                  NurbsCurveResult *result) const {
   const TransformState *net_transform = data.get_net_transform(trav);
   const TransformState *camera_transform = trav->get_camera_transform();
@@ -468,21 +464,21 @@ render_billboard(CullTraverser *trav, CullTraverserData &data,
   // either side.
   PT(GeomVertexData) vdata = new GeomVertexData
     ("rope", get_format(false), Geom::UH_stream);
-  
-  compute_billboard_vertices(vdata, camera_vec, 
+
+  compute_billboard_vertices(vdata, camera_vec,
                              curve_segments, num_curve_verts, result);
-  
+
   // Since this will be a nonindexed primitive, no need to pre-reserve
   // the number of vertices.
   PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_stream);
   CurveSegments::const_iterator si;
   for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
     const CurveSegment &segment = (*si);
-    
+
     strip->add_next_vertices(segment.size() * 2);
     strip->close_primitive();
   }
-  
+
   PT(Geom) geom = new Geom(vdata);
   geom->add_primitive(strip);
 
@@ -490,12 +486,10 @@ render_billboard(CullTraverser *trav, CullTraverserData &data,
   if (get_use_vertex_color()) {
     state = state->add_attrib(ColorAttrib::make_vertex());
   }
-  
-  CullableObject *object = 
+
+  CullableObject *object =
     new CullableObject(geom, state,
-                       data.get_net_transform(trav),
-                       data.get_modelview_transform(trav),
-                       trav->get_scene());
+                       data.get_internal_transform(trav));
   trav->get_cull_handler()->record_object(object, trav);
 }
 
@@ -509,7 +503,7 @@ render_billboard(CullTraverser *trav, CullTraverserData &data,
 //               determines the diameter of the tube.
 ////////////////////////////////////////////////////////////////////
 void RopeNode::
-render_tube(CullTraverser *trav, CullTraverserData &data, 
+render_tube(CullTraverser *trav, CullTraverserData &data,
             NurbsCurveResult *result) const {
   CurveSegments curve_segments;
   int num_curve_verts = get_connected_segments(curve_segments, result);
@@ -522,10 +516,10 @@ render_tube(CullTraverser *trav, CullTraverserData &data,
 
   PT(GeomVertexData) vdata = new GeomVertexData
     ("rope", get_format(true), Geom::UH_stream);
-  
-  compute_tube_vertices(vdata, num_verts_per_slice, 
+
+  compute_tube_vertices(vdata, num_verts_per_slice,
                         curve_segments, num_curve_verts, result);
-  
+
   // Finally, go through and build up the index array, to tie all the
   // triangle strips together.  This is difficult to pre-calculate the
   // number of vertices we'll use, so we'll just let it dynamically
@@ -535,20 +529,20 @@ render_tube(CullTraverser *trav, CullTraverserData &data,
   CurveSegments::const_iterator si;
   for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
     const CurveSegment &segment = (*si);
-    
+
     for (int s = 0; s < num_slices; ++s) {
       int s1 = (s + 1) % num_verts_per_slice;
-      
+
       for (size_t j = 0; j < segment.size(); ++j) {
         strip->add_vertex((vi + j) * num_verts_per_slice + s);
         strip->add_vertex((vi + j) * num_verts_per_slice + s1);
       }
-      
+
       strip->close_primitive();
     }
     vi += (int)segment.size();
   }
-  
+
   PT(Geom) geom = new Geom(vdata);
   geom->add_primitive(strip);
 
@@ -556,12 +550,10 @@ render_tube(CullTraverser *trav, CullTraverserData &data,
   if (get_use_vertex_color()) {
     state = state->add_attrib(ColorAttrib::make_vertex());
   }
-  
-  CullableObject *object = 
+
+  CullableObject *object =
     new CullableObject(geom, state,
-                       data.get_net_transform(trav),
-                       data.get_modelview_transform(trav),
-                       trav->get_scene());
+                       data.get_internal_transform(trav));
   trav->get_cull_handler()->record_object(object, trav);
 }
 
@@ -598,7 +590,7 @@ get_connected_segments(RopeNode::CurveSegments &curve_segments,
     LPoint3 point;
     result->eval_segment_point(segment, 0.0f, point);
 
-    if (curve_segment == (CurveSegment *)NULL || 
+    if (curve_segment == (CurveSegment *)NULL ||
         !point.almost_equal(last_point)) {
       // If the first point of this segment is different from the last
       // point of the previous segment, end the previous segment and
@@ -610,13 +602,13 @@ get_connected_segments(RopeNode::CurveSegments &curve_segments,
       vtx._p = point;
       vtx._t = result->get_segment_t(segment, 0.0f);
       if (use_vertex_color) {
-        result->eval_segment_extended_points(segment, 0.0f, 
-                                             get_vertex_color_dimension(), 
+        result->eval_segment_extended_points(segment, 0.0f,
+                                             get_vertex_color_dimension(),
                                              &vtx._c[0], 4);
       }
       if (use_vertex_thickness) {
-        vtx._thickness = 
-          result->eval_segment_extended_point(segment, 0.0f, 
+        vtx._thickness =
+          result->eval_segment_extended_point(segment, 0.0f,
                                               get_vertex_thickness_dimension());
       }
 
@@ -632,13 +624,13 @@ get_connected_segments(RopeNode::CurveSegments &curve_segments,
       result->eval_segment_point(segment, t, vtx._p);
       vtx._t = result->get_segment_t(segment, t);
       if (use_vertex_color) {
-        result->eval_segment_extended_points(segment, t, 
+        result->eval_segment_extended_points(segment, t,
                                              get_vertex_color_dimension(),
                                              &vtx._c[0], 4);
       }
       if (use_vertex_thickness) {
-        vtx._thickness = 
-          result->eval_segment_extended_point(segment, t, 
+        vtx._thickness =
+          result->eval_segment_extended_point(segment, t,
                                               get_vertex_thickness_dimension());
       }
 
@@ -868,7 +860,7 @@ compute_tube_vertices(GeomVertexData *vdata,
 //               point in the segment.
 ////////////////////////////////////////////////////////////////////
 void RopeNode::
-compute_tangent(LVector3 &tangent, const RopeNode::CurveSegment &segment, 
+compute_tangent(LVector3 &tangent, const RopeNode::CurveSegment &segment,
                 size_t j, NurbsCurveResult *result) {
   // First, try to evaluate the tangent at the curve.  This gives
   // better results at the ends at the endpoints where the tangent
@@ -908,17 +900,17 @@ compute_uv_t(PN_stdfloat &dist, const RopeNode::UVMode &uv_mode,
   switch (uv_mode) {
   case UV_none:
     return 0.0f;
-    
+
   case UV_parametric:
     return segment[j]._t * uv_scale;
-    
+
   case UV_distance:
     if (j != 0) {
       LVector3 vec = segment[j]._p - segment[j - 1]._p;
       dist += vec.length();
     }
     return dist * uv_scale;
-    
+
   case UV_distance2:
     if (j != 0) {
       LVector3 vec = segment[j]._p - segment[j - 1]._p;
@@ -929,7 +921,7 @@ compute_uv_t(PN_stdfloat &dist, const RopeNode::UVMode &uv_mode,
 
   return 0.0f;
 }
-  
+
 ////////////////////////////////////////////////////////////////////
 //     Function: RopeNode::register_with_read_factory
 //       Access: Public, Static

+ 18 - 20
panda/src/parametrics/sheetNode.cxx

@@ -155,13 +155,13 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
     NurbsSurfaceEvaluator *surface = get_surface();
     if (surface != (NurbsSurfaceEvaluator *)NULL) {
       PT(NurbsSurfaceResult) result = surface->evaluate(data._node_path.get_node_path());
-      
+
       if (result->get_num_u_segments() > 0 && result->get_num_v_segments() > 0) {
         render_sheet(trav, data, result);
       }
     }
   }
-  
+
   return true;
 }
 
@@ -183,7 +183,7 @@ is_renderable() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: SheetNode::output
 //       Access: Public, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 void SheetNode::
 output(ostream &out) const {
@@ -199,7 +199,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 //     Function: SheetNode::write
 //       Access: Public, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 void SheetNode::
 write(ostream &out, int indent_level) const {
@@ -241,8 +241,8 @@ compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
                         int &internal_vertices,
                         int pipeline_stage,
                         Thread *current_thread) const {
-  PT(BoundingVolume) bounds = 
-    do_recompute_bounds(NodePath((PandaNode *)this), pipeline_stage, 
+  PT(BoundingVolume) bounds =
+    do_recompute_bounds(NodePath((PandaNode *)this), pipeline_stage,
                         current_thread);
 
   internal_bounds = bounds;
@@ -255,7 +255,7 @@ compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
 //  Description: Does the actual internal recompute.
 ////////////////////////////////////////////////////////////////////
 PT(BoundingVolume) SheetNode::
-do_recompute_bounds(const NodePath &rel_to, int pipeline_stage, 
+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
@@ -263,12 +263,12 @@ do_recompute_bounds(const NodePath &rel_to, int pipeline_stage,
 
   // First, get ourselves a fresh, empty bounding volume.
   PT(BoundingVolume) bound = new BoundingSphere;
-  
+
   NurbsSurfaceEvaluator *surface = get_surface();
   if (surface != (NurbsSurfaceEvaluator *)NULL) {
     NurbsSurfaceEvaluator::Vert3Array verts;
     get_surface()->get_vertices(verts, rel_to);
-    
+
     GeometricBoundingVolume *gbv;
     DCAST_INTO_R(gbv, bound, bound);
     gbv->around(&verts[0], &verts[0] + verts.size());
@@ -283,7 +283,7 @@ do_recompute_bounds(const NodePath &rel_to, int pipeline_stage,
 //               length.
 ////////////////////////////////////////////////////////////////////
 void SheetNode::
-render_sheet(CullTraverser *trav, CullTraverserData &data, 
+render_sheet(CullTraverser *trav, CullTraverserData &data,
              NurbsSurfaceResult *result) {
   bool use_vertex_color = get_use_vertex_color();
 
@@ -312,12 +312,12 @@ render_sheet(CullTraverser *trav, CullTraverserData &data,
     for (int uni = 0; uni <= num_u_verts; uni++) {
       PN_stdfloat u0 = (PN_stdfloat)uni / (PN_stdfloat)num_u_verts;
       PN_stdfloat u0_tc = result->get_segment_u(ui, u0);
-      
+
       for (int vi = 0; vi < num_v_segments; vi++) {
         for (int vni = 0; vni < num_v_verts; vni++) {
           PN_stdfloat v = (PN_stdfloat)vni / (PN_stdfloat)(num_v_verts - 1);
           PN_stdfloat v_tc = result->get_segment_v(vi, v);
-          
+
           LPoint3 point;
           LVector3 norm;
           result->eval_segment_point(ui, vi, u0, v, point);
@@ -325,7 +325,7 @@ render_sheet(CullTraverser *trav, CullTraverserData &data,
           vertex.add_data3(point);
           normal.add_data3(norm);
           texcoord.add_data2(u0_tc, v_tc);
-          
+
           if (use_vertex_color) {
             LColor c0;
             result->eval_segment_extended_points(ui, vi, u0, v, 0, &c0[0], 4);
@@ -336,7 +336,7 @@ render_sheet(CullTraverser *trav, CullTraverserData &data,
     }
   }
   nassertv(vdata->get_num_rows() == expected_num_vertices);
-  
+
   PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_stream);
 
   int expected_num_tristrips = num_u_segments * num_u_verts * num_v_segments;
@@ -364,7 +364,7 @@ render_sheet(CullTraverser *trav, CullTraverserData &data,
     }
   }
   nassertv(strip->get_num_vertices() == expected_prim_vertices);
-  
+
   PT(Geom) geom = new Geom(vdata);
   geom->add_primitive(strip);
 
@@ -372,12 +372,10 @@ render_sheet(CullTraverser *trav, CullTraverserData &data,
   if (use_vertex_color) {
     state = state->add_attrib(ColorAttrib::make_vertex());
   }
-  
-  CullableObject *object = 
+
+  CullableObject *object =
     new CullableObject(geom, state,
-                       data.get_net_transform(trav),
-                       data.get_modelview_transform(trav),
-                       trav->get_scene());
+                       data.get_internal_transform(trav));
   trav->get_cull_handler()->record_object(object, trav);
 }
 

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

@@ -108,12 +108,12 @@ ResultGraphBuilder(PandaNode *root_node) :
 ////////////////////////////////////////////////////////////////////
 void CullBin::ResultGraphBuilder::
 add_object(CullableObject *object) {
-  if (_current_transform != object->_modelview_transform ||
+  if (_current_transform != object->_internal_transform ||
       _current_state != object->_state) {
     // Create a new GeomNode to hold the net transform and state.  We
     // choose to create a new GeomNode for each new state, to make it
     // clearer to the observer when the state changes.
-    _current_transform = object->_modelview_transform;
+    _current_transform = object->_internal_transform;
     _current_state = object->_state;
     _current_node = new GeomNode("object_" + format_string(_object_index));
     _root_node->add_child(_current_node);

+ 3 - 4
panda/src/pgraph/cullHandler.cxx

@@ -22,7 +22,7 @@
 ////////////////////////////////////////////////////////////////////
 //     Function: CullHandler::Constructor
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 CullHandler::
 CullHandler() {
@@ -31,7 +31,7 @@ CullHandler() {
 ////////////////////////////////////////////////////////////////////
 //     Function: CullHandler::Destructor
 //       Access: Public, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 CullHandler::
 ~CullHandler() {
@@ -50,7 +50,7 @@ CullHandler::
 ////////////////////////////////////////////////////////////////////
 void CullHandler::
 record_object(CullableObject *object, const CullTraverser *traverser) {
-  nout << *object->_geom << " " << *object->_modelview_transform << " " 
+  nout << *object->_geom << " " << *object->_internal_transform << " "
        << *object->_state << "\n";
   delete object;
 }
@@ -65,4 +65,3 @@ record_object(CullableObject *object, const CullTraverser *traverser) {
 void CullHandler::
 end_traverse() {
 }
-

+ 21 - 22
panda/src/pgraph/cullPlanes.cxx

@@ -116,11 +116,11 @@ apply_state(const CullTraverser *trav, const CullTraverserData *data,
           if (net_transform == (TransformState *)NULL) {
             net_transform = data->get_net_transform(trav);
           }
-          
+
           PlaneNode *plane_node = DCAST(PlaneNode, clip_plane.node());
-          CPT(TransformState) new_transform = 
+          CPT(TransformState) new_transform =
             net_transform->invert_compose(clip_plane.get_net_transform());
-          
+
           LPlane plane = plane_node->get_plane() * new_transform->get_mat();
           new_planes->_planes[clip_plane] = new BoundingPlane(-plane);
         }
@@ -174,17 +174,17 @@ apply_state(const CullTraverser *trav, const CullTraverserData *data,
         ccp[2] = occluder_node->get_vertex(2) * composed_mat;
         ccp[3] = occluder_node->get_vertex(3) * composed_mat;
 
-        LPoint3 ccp_min(min(min(ccp[0][0], ccp[1][0]), 
+        LPoint3 ccp_min(min(min(ccp[0][0], ccp[1][0]),
                      min(ccp[2][0], ccp[3][0])),
-                 min(min(ccp[0][1], ccp[1][1]), 
+                 min(min(ccp[0][1], ccp[1][1]),
                      min(ccp[2][1], ccp[3][1])),
-                 min(min(ccp[0][2], ccp[1][2]), 
+                 min(min(ccp[0][2], ccp[1][2]),
                      min(ccp[2][2], ccp[3][2])));
-        LPoint3 ccp_max(max(max(ccp[0][0], ccp[1][0]), 
+        LPoint3 ccp_max(max(max(ccp[0][0], ccp[1][0]),
                      max(ccp[2][0], ccp[3][0])),
-                 max(max(ccp[0][1], ccp[1][1]), 
+                 max(max(ccp[0][1], ccp[1][1]),
                      max(ccp[2][1], ccp[3][1])),
-                 max(max(ccp[0][2], ccp[1][2]), 
+                 max(max(ccp[0][2], ccp[1][2]),
                      max(ccp[2][2], ccp[3][2])));
 
         occluder_gbv = new BoundingBox(ccp_min, ccp_max);
@@ -209,7 +209,7 @@ apply_state(const CullTraverser *trav, const CullTraverserData *data,
         points_near[2] = occluder_node->get_vertex(2) * occluder_mat_cull;
         points_near[3] = occluder_node->get_vertex(3) * occluder_mat_cull;
         LPlane plane(points_near[0], points_near[1], points_near[2]);
-        
+
         if (plane.get_normal().dot(LVector3::forward()) >= 0.0) {
           if (occluder_node->is_double_sided()) {
             swap(points_near[0], points_near[3]);
@@ -294,22 +294,21 @@ apply_state(const CullTraverser *trav, const CullTraverserData *data,
 
         // With these points, construct the bounding frustum of the
         // occluded region.
-        PT(BoundingHexahedron) frustum = 
-          new BoundingHexahedron(points_far[1], points_far[2], points_far[3], points_far[0],  
+        PT(BoundingHexahedron) frustum =
+          new BoundingHexahedron(points_far[1], points_far[2], points_far[3], points_far[0],
                                  points_near[1], points_near[2], points_near[3], points_near[0]);
 
         new_planes->_occluders[occluder] = frustum;
-        
+
         if (show_occluder_volumes) {
           // Draw the frustum for visualization.
           nassertr(net_transform != NULL, new_planes);
-          trav->draw_bounding_volume(frustum, net_transform, 
-                                     data->get_modelview_transform(trav));
+          trav->draw_bounding_volume(frustum, data->get_internal_transform(trav));
         }
       }
     }
   }
-    
+
   return new_planes;
 }
 
@@ -330,13 +329,13 @@ apply_state(const CullTraverser *trav, const CullTraverserData *data,
 CPT(CullPlanes) CullPlanes::
 do_cull(int &result, CPT(RenderState) &state,
         const GeometricBoundingVolume *node_gbv) const {
-  result = 
+  result =
     BoundingVolume::IF_all | BoundingVolume::IF_possible | BoundingVolume::IF_some;
 
   CPT(ClipPlaneAttrib) orig_cpa = DCAST(ClipPlaneAttrib, state->get_attrib(ClipPlaneAttrib::get_class_slot()));
 
   CPT(CullPlanes) new_planes = this;
-  
+
   if (orig_cpa == (ClipPlaneAttrib *)NULL) {
     // If there are no clip planes in the state, the node is completely
     // in front of all zero of the clip planes.  (This can happen if
@@ -385,7 +384,7 @@ do_cull(int &result, CPT(RenderState) &state,
       // The node is completely in front of this occluder.  We don't
       // need to consider this occluder ever again for any descendents of
       // this node.
-      
+
       // Reverse the sense of the test, because an occluder volume is
       // the inverse of a cull plane volume: it describes the volume
       // that is to be culled, not the volume that is to be kept.
@@ -403,7 +402,7 @@ do_cull(int &result, CPT(RenderState) &state,
 
     result &= occluder_result;
   }
-    
+
   return new_planes;
 }
 
@@ -456,11 +455,11 @@ remove_occluder(const NodePath &occluder) const {
 ////////////////////////////////////////////////////////////////////
 //     Function: CullPlanes::write
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 void CullPlanes::
 write(ostream &out) const {
-  out << "CullPlanes (" << _planes.size() << " planes and " 
+  out << "CullPlanes (" << _planes.size() << " planes and "
       << _occluders.size() << " occluders):\n";
   Planes::const_iterator pi;
   for (pi = _planes.begin(); pi != _planes.end(); ++pi) {

+ 8 - 13
panda/src/pgraph/cullTraverser.cxx

@@ -252,20 +252,19 @@ end_traverse() {
 ////////////////////////////////////////////////////////////////////
 void CullTraverser::
 draw_bounding_volume(const BoundingVolume *vol,
-                     const TransformState *net_transform,
-                     const TransformState *modelview_transform) const {
+                     const TransformState *internal_transform) const {
   PT(Geom) bounds_viz = make_bounds_viz(vol);
 
   if (bounds_viz != (Geom *)NULL) {
     _geoms_pcollector.add_level(2);
     CullableObject *outer_viz =
       new CullableObject(bounds_viz, get_bounds_outer_viz_state(),
-                         net_transform, modelview_transform, get_scene());
+                         internal_transform);
     _cull_handler->record_object(outer_viz, this);
 
     CullableObject *inner_viz =
       new CullableObject(bounds_viz, get_bounds_inner_viz_state(),
-                         net_transform, modelview_transform, get_scene());
+                         internal_transform);
     _cull_handler->record_object(inner_viz, this);
   }
 }
@@ -292,8 +291,7 @@ is_in_view(CullTraverserData &data) {
 void CullTraverser::
 show_bounds(CullTraverserData &data, bool tight) {
   PandaNode *node = data.node();
-  CPT(TransformState) net_transform = data.get_net_transform(this);
-  CPT(TransformState) modelview_transform = data.get_modelview_transform(this);
+  CPT(TransformState) internal_transform = data.get_internal_transform(this);
 
   if (tight) {
     PT(Geom) bounds_viz = make_tight_bounds_viz(node);
@@ -302,24 +300,21 @@ show_bounds(CullTraverserData &data, bool tight) {
       _geoms_pcollector.add_level(1);
       CullableObject *outer_viz =
         new CullableObject(bounds_viz, get_bounds_outer_viz_state(),
-                           net_transform, modelview_transform,
-                           get_scene());
+                           internal_transform);
       _cull_handler->record_object(outer_viz, this);
     }
 
   } else {
-    draw_bounding_volume(node->get_bounds(),
-                         net_transform, modelview_transform);
+    draw_bounding_volume(node->get_bounds(), internal_transform);
 
     if (node->is_geom_node()) {
       // Also show the bounding volumes of included Geoms.
-      net_transform = net_transform->compose(node->get_transform());
-      modelview_transform = modelview_transform->compose(node->get_transform());
+      internal_transform = internal_transform->compose(node->get_transform());
       GeomNode *gnode = DCAST(GeomNode, node);
       int num_geoms = gnode->get_num_geoms();
       for (int i = 0; i < num_geoms; ++i) {
         draw_bounding_volume(gnode->get_geom(i)->get_bounds(),
-                             net_transform, modelview_transform);
+                             internal_transform);
       }
     }
   }

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

@@ -27,7 +27,6 @@
 #include "drawMask.h"
 #include "typedReferenceCount.h"
 #include "pStatCollector.h"
-#include "cullTraverserData.h"
 #include "fogAttrib.h"
 
 class GraphicsStateGuardian;
@@ -90,8 +89,7 @@ PUBLISHED:
   INLINE static void flush_level();
 
   void draw_bounding_volume(const BoundingVolume *vol,
-                            const TransformState *net_transform,
-                            const TransformState *modelview_transform) const;
+                            const TransformState *internal_transform) const;
 
 protected:
   INLINE void do_traverse(CullTraverserData &data);
@@ -148,9 +146,8 @@ private:
   static TypeHandle _type_handle;
 };
 
+#include "cullTraverserData.h"
+
 #include "cullTraverser.I"
 
 #endif
-
-
-

+ 22 - 0
panda/src/pgraph/cullTraverserData.I

@@ -136,6 +136,28 @@ node_reader() const {
   return &_node_reader;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CullTraverserData::get_modelview_transform
+//       Access: Published
+//  Description: Returns the modelview transform: the relative
+//               transform from the camera to the model.
+////////////////////////////////////////////////////////////////////
+INLINE CPT(TransformState) CullTraverserData::
+get_modelview_transform(const CullTraverser *trav) const {
+  return trav->get_world_transform()->compose(_net_transform);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullTraverserData::get_internal_transform
+//       Access: Published
+//  Description: Returns the internal transform: the modelview
+//               transform in the GSG's internal coordinate system.
+////////////////////////////////////////////////////////////////////
+INLINE CPT(TransformState) CullTraverserData::
+get_internal_transform(const CullTraverser *trav) const {
+  return trav->get_scene()->get_cs_world_transform()->compose(_net_transform);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CullTraverserData::get_net_transform
 //       Access: Published

+ 0 - 11
panda/src/pgraph/cullTraverserData.cxx

@@ -28,17 +28,6 @@
 #include "renderState.h"
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: CullTraverserData::get_modelview_transform
-//       Access: Published
-//  Description: Returns the modelview transform: the relative
-//               transform from the camera to the model.
-////////////////////////////////////////////////////////////////////
-CPT(TransformState) CullTraverserData::
-get_modelview_transform(const CullTraverser *trav) const {
-  return trav->get_world_transform()->compose(_net_transform);
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: CullTraverserData::apply_transform_and_state
 //       Access: Published

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

@@ -50,8 +50,8 @@ public:
                            GeometricBoundingVolume *view_frustum,
                            Thread *current_thread);
   INLINE CullTraverserData(const CullTraverserData &copy);
-  INLINE void operator = (const CullTraverserData &copy); 
-  INLINE CullTraverserData(const CullTraverserData &parent, 
+  INLINE void operator = (const CullTraverserData &copy);
+  INLINE CullTraverserData(const CullTraverserData &parent,
                            PandaNode *child);
   INLINE ~CullTraverserData();
 
@@ -63,15 +63,16 @@ public:
   INLINE const PandaNodePipelineReader *node_reader() const;
 
 PUBLISHED:
-  CPT(TransformState) get_modelview_transform(const CullTraverser *trav) const;
+  INLINE CPT(TransformState) get_modelview_transform(const CullTraverser *trav) const;
+  INLINE CPT(TransformState) get_internal_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_this_node_hidden(const DrawMask &camera_mask) const;
 
   void apply_transform_and_state(CullTraverser *trav);
-  void apply_transform_and_state(CullTraverser *trav, 
-                                 CPT(TransformState) node_transform, 
+  void apply_transform_and_state(CullTraverser *trav,
+                                 CPT(TransformState) node_transform,
                                  CPT(RenderState) node_state,
                                  CPT(RenderEffects) node_effects,
                                  const RenderAttrib *off_clip_planes);
@@ -91,6 +92,8 @@ private:
   static CPT(RenderState) get_fake_view_frustum_cull_state();
 };
 
+#include "cullTraverser.h"
+
 #include "cullTraverserData.I"
 
 #endif

+ 0 - 30
panda/src/pgraph/cullableObject.I

@@ -34,35 +34,9 @@ CullableObject() {
 ////////////////////////////////////////////////////////////////////
 INLINE CullableObject::
 CullableObject(const Geom *geom, const RenderState *state,
-               const TransformState *net_transform,
-               const TransformState *modelview_transform,
-               SceneSetup *scene_setup) :
-  _geom(geom),
-  _state(state),
-  _net_transform(net_transform),
-  _modelview_transform(modelview_transform),
-  _internal_transform(scene_setup->get_cs_transform()->compose(modelview_transform))
-{
-#ifdef DO_MEMORY_USAGE
-  MemoryUsage::update_type(this, get_class_type());
-#endif
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CullableObject::Constructor
-//       Access: Public
-//  Description: Creates a CullableObject based the indicated geom,
-//               with the indicated render state and transform.
-////////////////////////////////////////////////////////////////////
-INLINE CullableObject::
-CullableObject(const Geom *geom, const RenderState *state,
-               const TransformState *net_transform,
-               const TransformState *modelview_transform,
                const TransformState *internal_transform) :
   _geom(geom),
   _state(state),
-  _net_transform(net_transform),
-  _modelview_transform(modelview_transform),
   _internal_transform(internal_transform)
 {
 #ifdef DO_MEMORY_USAGE
@@ -81,8 +55,6 @@ CullableObject(const CullableObject &copy) :
   _munger(copy._munger),
   _munged_data(copy._munged_data),
   _state(copy._state),
-  _net_transform(copy._net_transform),
-  _modelview_transform(copy._modelview_transform),
   _internal_transform(copy._internal_transform)
 {
 #ifdef DO_MEMORY_USAGE
@@ -101,8 +73,6 @@ operator = (const CullableObject &copy) {
   _munger = copy._munger;
   _munged_data = copy._munged_data;
   _state = copy._state;
-  _net_transform = copy._net_transform;
-  _modelview_transform = copy._modelview_transform;
   _internal_transform = copy._internal_transform;
   _draw_callback = copy._draw_callback;
 }

+ 19 - 17
panda/src/pgraph/cullableObject.cxx

@@ -79,7 +79,7 @@ munge_geom(GraphicsStateGuardianBase *gsg,
 
       geom_rendering = geom_reader.get_geom_rendering();
       geom_rendering = _state->get_geom_rendering(geom_rendering);
-      geom_rendering = _modelview_transform->get_geom_rendering(geom_rendering);
+      geom_rendering = _internal_transform->get_geom_rendering(geom_rendering);
 
       if (geom_rendering & Geom::GR_point_bits) {
         if (geom_reader.get_primitive_type() != Geom::PT_points) {
@@ -237,7 +237,7 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
     }
   }
 
-  PN_stdfloat point_size = 1.0f;
+  PN_stdfloat point_size = 1;
   bool perspective = false;
   const RenderModeAttrib *render_mode = DCAST(RenderModeAttrib, _state->get_attrib(RenderModeAttrib::get_class_slot()));
   if (render_mode != (RenderModeAttrib *)NULL) {
@@ -309,11 +309,15 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
     }
   }
 
-  const LMatrix4 &modelview = _modelview_transform->get_mat();
+  CoordinateSystem internal_cs = gsg->get_internal_coordinate_system();
+  LMatrix4 internal = _internal_transform->get_mat();
+  PN_stdfloat scale = _internal_transform->get_scale()[1];
 
   SceneSetup *scene = traverser->get_scene();
   const Lens *lens = scene->get_lens();
-  const LMatrix4 &projection = lens->get_projection_mat();
+  LMatrix4 projection =
+    LMatrix4::convert_mat(internal_cs, lens->get_coordinate_system()) *
+                                       lens->get_projection_mat();
 
   int viewport_width = scene->get_viewport_width();
   int viewport_height = scene->get_viewport_height();
@@ -324,10 +328,10 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
   if (perspective) {
     height_projection =
       LMatrix4::convert_mat(CS_yup_right, lens->get_coordinate_system()) *
-      projection;
+                                          lens->get_projection_mat();
   }
 
-  LMatrix4 render_transform = modelview * projection;
+  LMatrix4 render_transform = internal * projection;
   LMatrix4 inv_render_transform;
   inv_render_transform.invert_from(render_transform);
 
@@ -357,15 +361,16 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
     int vi = 0;
     while (!vertex.is_at_end()) {
       // Get the point in eye-space coordinates.
-      LPoint3 eye = modelview.xform_point(vertex.get_data3());
+      LPoint3 eye = internal.xform_point(vertex.get_data3());
+      PN_stdfloat dist = gsg->compute_distance_to(eye);
       points[vi]._eye = eye;
-      points[vi]._dist = gsg->compute_distance_to(points[vi]._eye);
+      points[vi]._dist = dist;
 
       // The point in clip coordinates.
       LPoint4 p4 = LPoint4(eye[0], eye[1], eye[2], 1.0f) * projection;
 
       if (has_size) {
-        point_size = size.get_data1f();
+        point_size = size.get_data1();
       }
 
       PN_stdfloat scale_y = point_size;
@@ -374,7 +379,6 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
         // height in 3-d units.  To arrange that, we need to figure out
         // the appropriate scaling factor based on the current viewport
         // and projection matrix.
-        PN_stdfloat scale = _modelview_transform->get_scale()[1];
         LVector3 height(0.0f, point_size * scale, scale);
         height = height * height_projection;
         scale_y = height[1] * viewport_height;
@@ -382,7 +386,7 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
         // We should then divide the radius by the distance from the
         // camera plane, to emulate the glPointParameters() behavior.
         if (!lens->is_orthographic()) {
-          scale_y /= gsg->compute_distance_to(eye);
+          scale_y /= dist;
         }
       }
 
@@ -392,7 +396,7 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
 
       PN_stdfloat scale_x = scale_y;
       if (has_aspect_ratio) {
-        scale_x *= aspect_ratio.get_data1f();
+        scale_x *= aspect_ratio.get_data1();
       }
 
       // Define the first two corners based on the scales in X and Y.
@@ -401,7 +405,7 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
 
       if (has_rotate) {
         // If we have a rotate factor, apply it to those two corners.
-        PN_stdfloat r = rotate.get_data1f();
+        PN_stdfloat r = rotate.get_data1();
         LMatrix3 mat = LMatrix3::rotate_mat(r);
         c0 = c0 * mat;
         c1 = c1 * mat;
@@ -474,11 +478,9 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
   }
 
   // Determine the format we should use to store the indices.
+  // Don't choose NT_uint8, as Direct3D 9 doesn't support it.
   const GeomVertexArrayFormat *new_prim_format = NULL;
-  if (new_verts < 0xff) {
-    new_prim_format = GeomPrimitive::get_index_format(GeomEnums::NT_uint8);
-
-  } else if (new_verts < 0xffff) {
+  if (new_verts < 0xffff) {
     new_prim_format = GeomPrimitive::get_index_format(GeomEnums::NT_uint16);
 
   } else {

+ 0 - 8
panda/src/pgraph/cullableObject.h

@@ -50,12 +50,6 @@ class EXPCL_PANDA_PGRAPH CullableObject
 public:
   INLINE CullableObject();
   INLINE CullableObject(const Geom *geom, const RenderState *state,
-                        const TransformState *net_transform,
-                        const TransformState *modelview_transform,
-                        SceneSetup *scene_setup);
-  INLINE CullableObject(const Geom *geom, const RenderState *state,
-                        const TransformState *net_transform,
-                        const TransformState *modelview_transform,
                         const TransformState *internal_transform);
 
   INLINE CullableObject(const CullableObject &copy);
@@ -82,8 +76,6 @@ public:
   PT(GeomMunger) _munger;
   CPT(GeomVertexData) _munged_data;
   CPT(RenderState) _state;
-  CPT(TransformState) _net_transform;
-  CPT(TransformState) _modelview_transform;
   CPT(TransformState) _internal_transform;
   PT(CallbackObject) _draw_callback;
 

+ 2 - 5
panda/src/pgraph/geomNode.cxx

@@ -562,9 +562,7 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) {
   Geoms geoms = get_geoms(trav->get_current_thread());
   int num_geoms = geoms.get_num_geoms();
   trav->_geoms_pcollector.add_level(num_geoms);
-  CPT(TransformState) net_transform = data.get_net_transform(trav);
-  CPT(TransformState) modelview_transform = data.get_modelview_transform(trav);
-  CPT(TransformState) internal_transform = trav->get_scene()->get_cs_transform()->compose(modelview_transform);
+  CPT(TransformState) internal_transform = data.get_internal_transform(trav);
 
   for (int i = 0; i < num_geoms; i++) {
     const Geom *geom = geoms.get_geom(i);
@@ -611,8 +609,7 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) {
     }
 
     CullableObject *object =
-      new CullableObject(geom, state, net_transform,
-                         modelview_transform, internal_transform);
+      new CullableObject(geom, state, internal_transform);
     trav->get_cull_handler()->record_object(object, trav);
   }
 }

+ 1 - 0
panda/src/pgraph/geomNode.h

@@ -73,6 +73,7 @@ PUBLISHED:
   INLINE CPT(Geom) get_geom(int n) const;
   MAKE_SEQ(get_geoms, get_num_geoms, get_geom);
   INLINE PT(Geom) modify_geom(int n);
+  MAKE_SEQ(modify_geoms, get_num_geoms, modify_geom);
   INLINE const RenderState *get_geom_state(int n) const;
   MAKE_SEQ(get_geom_states, get_num_geoms, get_geom_state);
   INLINE void set_geom_state(int n, const RenderState *state);

+ 27 - 0
panda/src/pgraph/nodePath.I

@@ -109,6 +109,33 @@ operator = (const NodePath &copy) {
   _error_type = copy._error_type;
 }
 
+#ifdef USE_MOVE_SEMANTICS
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::Move Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE NodePath::
+NodePath(NodePath &&from) NOEXCEPT :
+  _head(move(from._head)),
+  _backup_key(from._backup_key),
+  _error_type(from._error_type)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::Move Assignment Operator
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void NodePath::
+operator = (NodePath &&from) NOEXCEPT {
+  _head = move(from._head);
+  _backup_key = from._backup_key;
+  _error_type = from._error_type;
+}
+#endif  // USE_MOVE_SEMANTICS
+
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::not_found named constructor
 //       Access: Published, Static

+ 5 - 0
panda/src/pgraph/nodePath.h

@@ -180,6 +180,11 @@ PUBLISHED:
   INLINE NodePath(const NodePath &copy);
   INLINE void operator = (const NodePath &copy);
 
+#ifdef USE_MOVE_SEMANTICS
+  INLINE NodePath(NodePath &&from) NOEXCEPT;
+  INLINE void operator = (NodePath &&from) NOEXCEPT;
+#endif
+
   EXTENSION(NodePath __copy__() const);
   EXTENSION(PyObject *__deepcopy__(PyObject *self, PyObject *memo) const);
   EXTENSION(PyObject *__reduce__(PyObject *self) const);

+ 6 - 10
panda/src/pgraph/occluderNode.cxx

@@ -164,20 +164,16 @@ bool OccluderNode::
 cull_callback(CullTraverser *trav, CullTraverserData &data) {
   // Normally, an OccluderNode is invisible.  But if someone shows it,
   // we will draw a visualization, a checkerboard-textured polygon.
-  CullableObject *occluder_viz = 
-    new CullableObject(get_occluder_viz(trav, data), get_occluder_viz_state(trav, data), 
-                       data.get_net_transform(trav),
-                       data.get_modelview_transform(trav),
-                       trav->get_scene());
+  CullableObject *occluder_viz =
+    new CullableObject(get_occluder_viz(trav, data), get_occluder_viz_state(trav, data),
+                       data.get_internal_transform(trav));
   trav->get_cull_handler()->record_object(occluder_viz, trav);
 
   // Also get the frame.
   nassertr(_frame_viz != (Geom *)NULL, false);
-  CullableObject *frame_viz = 
-    new CullableObject(_frame_viz, get_frame_viz_state(trav, data), 
-                       data.get_net_transform(trav),
-                       data.get_modelview_transform(trav),
-                       trav->get_scene());
+  CullableObject *frame_viz =
+    new CullableObject(_frame_viz, get_frame_viz_state(trav, data),
+                       data.get_internal_transform(trav));
   trav->get_cull_handler()->record_object(frame_viz, trav);
 
   // Now carry on to render our child nodes.

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

@@ -99,7 +99,7 @@ PlaneNode(const PlaneNode &copy) :
 ////////////////////////////////////////////////////////////////////
 //     Function: PlaneNode::output
 //       Access: Public, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 void PlaneNode::
 output(ostream &out) const {
@@ -166,11 +166,9 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
   // Normally, a PlaneNode is invisible.  But if someone shows it, we
   // will draw a visualization, a nice yellow wireframe.
 
-  CullableObject *plane_viz = 
-    new CullableObject(get_viz(trav, data), data._state, 
-                       data.get_net_transform(trav),
-                       data.get_modelview_transform(trav),
-                       trav->get_scene());
+  CullableObject *plane_viz =
+    new CullableObject(get_viz(trav, data), data._state,
+                       data.get_internal_transform(trav));
   trav->get_cull_handler()->record_object(plane_viz, trav);
 
   // Now carry on to render our child nodes.
@@ -219,7 +217,7 @@ compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
 PT(Geom) PlaneNode::
 get_viz(CullTraverser *trav, CullTraverserData &data) {
   CDLockedReader cdata(_cycler);
-  
+
   // Figure out whether we are looking at the front or the back of the
   // plane.
   const Lens *lens = trav->get_scene()->get_lens();
@@ -273,7 +271,7 @@ get_viz(CullTraverser *trav, CullTraverserData &data) {
   static const int num_segs = 10;
   a *= cdataw->_viz_scale / (num_segs * 2);
   b *= cdataw->_viz_scale / (num_segs * 2);
-  
+
   for (int x = -num_segs; x <= num_segs; ++x) {
     vertex.add_data3(plane.project(a * x - b * num_segs));
     vertex.add_data3(plane.project(a * x + b * num_segs));

+ 25 - 0
panda/src/pgraph/sceneSetup.I

@@ -28,6 +28,7 @@ SceneSetup() {
   _camera_transform = TransformState::make_identity();
   _world_transform = TransformState::make_identity();
   _cs_transform = TransformState::make_identity();
+  _cs_world_transform = TransformState::make_identity();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -316,3 +317,27 @@ INLINE const TransformState *SceneSetup::
 get_cs_transform() const {
   return _cs_transform;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: SceneSetup::set_cs_world_transform
+//       Access: Published
+//  Description: Specifies the position from the starting node
+//               relative to the camera, in the GSG's internal
+//               coordinate system.
+////////////////////////////////////////////////////////////////////
+INLINE void SceneSetup::
+set_cs_world_transform(const TransformState *cs_world_transform) {
+  _cs_world_transform = cs_world_transform;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SceneSetup::get_cs_world_transform
+//       Access: Published
+//  Description: Returns the position from the starting node
+//               relative to the camera, in the GSG's internal
+//               coordinate system.
+////////////////////////////////////////////////////////////////////
+INLINE const TransformState *SceneSetup::
+get_cs_world_transform() const {
+  return _cs_world_transform;
+}

+ 4 - 0
panda/src/pgraph/sceneSetup.h

@@ -74,6 +74,9 @@ PUBLISHED:
   INLINE void set_cs_transform(const TransformState *cs_transform);
   INLINE const TransformState *get_cs_transform() const;
 
+  INLINE void set_cs_world_transform(const TransformState *cs_world_transform);
+  INLINE const TransformState *get_cs_world_transform() const;
+
 private:
   DisplayRegion *_display_region;
   int _viewport_width;
@@ -87,6 +90,7 @@ private:
   CPT(TransformState) _camera_transform;
   CPT(TransformState) _world_transform;
   CPT(TransformState) _cs_transform;
+  CPT(TransformState) _cs_world_transform;
 
 public:
   static TypeHandle get_class_type() {

+ 3 - 5
panda/src/pgraphnodes/callbackNode.cxx

@@ -149,7 +149,7 @@ void CallbackNode::
 add_for_draw(CullTraverser *trav, CullTraverserData &data) {
   if (pgraph_cat.is_spam()) {
     pgraph_cat.spam()
-      << "Found " << *this << " in state " << *data._state 
+      << "Found " << *this << " in state " << *data._state
       << " draw_mask = " << data._draw_mask << "\n";
   }
 
@@ -158,11 +158,9 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) {
   // pass any Geoms, however.
   CallbackObject *cbobj = get_draw_callback();
   if (cbobj != (CallbackObject *)NULL) {
-    CullableObject *object = 
+    CullableObject *object =
       new CullableObject(NULL, data._state,
-                         data.get_net_transform(trav),
-                         data.get_modelview_transform(trav),
-                         trav->get_scene());
+                         data.get_internal_transform(trav));
     object->set_draw_callback(cbobj);
     trav->get_cull_handler()->record_object(object, trav);
   }

+ 2 - 4
panda/src/pgraphnodes/computeNode.cxx

@@ -105,7 +105,7 @@ void ComputeNode::
 add_for_draw(CullTraverser *trav, CullTraverserData &data) {
   if (pgraph_cat.is_spam()) {
     pgraph_cat.spam()
-      << "Found " << *this << " in state " << *data._state 
+      << "Found " << *this << " in state " << *data._state
       << " draw_mask = " << data._draw_mask << "\n";
   }
 
@@ -114,9 +114,7 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) {
   // any Geoms, however.
   CullableObject *object =
     new CullableObject(NULL, data._state,
-                         data.get_net_transform(trav),
-                         data.get_modelview_transform(trav),
-                         trav->get_scene());
+                       data.get_internal_transform(trav));
   object->set_draw_callback(_dispatcher);
   trav->get_cull_handler()->record_object(object, trav);
 }

+ 2 - 4
panda/src/pgraphnodes/nodeCullCallbackData.cxx

@@ -55,11 +55,9 @@ upcall() {
     // to pass any Geoms, however.
     CallbackObject *cbobj = cbnode->get_draw_callback();
     if (cbobj != (CallbackObject *)NULL) {
-      CullableObject *object = 
+      CullableObject *object =
         new CullableObject(NULL, _data._state,
-                           _data.get_net_transform(_trav),
-                           _data.get_modelview_transform(_trav),
-                           _trav->get_scene());
+                           _data.get_internal_transform(_trav));
       object->set_draw_callback(cbobj);
       _trav->get_cull_handler()->record_object(object, _trav);
     }

+ 4 - 5
panda/src/rocket/rocketRenderInterface.cxx

@@ -123,14 +123,13 @@ render_geom(const Geom* geom, const RenderState* state, const Rocket::Core::Vect
       << *state << ", translation (" << offset << ")\n";
   }
 
-  CPT(TransformState) net_transform, modelview_transform;
-  net_transform = _net_transform->compose(TransformState::make_pos(offset));
-  modelview_transform = _trav->get_world_transform()->compose(net_transform);
+  CPT(TransformState) internal_transform =
+    _trav->get_scene()->get_cs_world_transform()->compose(
+      _net_transform->compose(TransformState::make_pos(offset)));
 
   CullableObject *object =
     new CullableObject(geom, _net_state->compose(state),
-                       net_transform, modelview_transform,
-                       _trav->get_scene());
+                       internal_transform);
   _trav->get_cull_handler()->record_object(object, _trav);
 }
 

+ 50 - 52
panda/src/speedtree/speedTreeNode.cxx

@@ -332,7 +332,7 @@ add_instances_from(const SpeedTreeNode *other) {
     const InstanceList &other_instance_list = other->get_instance_list(ti);
     const STTree *tree = other_instance_list.get_tree();
     InstanceList &this_instance_list = add_tree(tree);
-    
+
     int num_instances = other_instance_list.get_num_instances();
     for (int i = 0; i < num_instances; ++i) {
       STTransform other_trans = other_instance_list.get_instance(i);
@@ -356,7 +356,7 @@ add_instances_from(const SpeedTreeNode *other, const TransformState *transform)
     const InstanceList &other_instance_list = other->get_instance_list(ti);
     const STTree *tree = other_instance_list.get_tree();
     InstanceList &this_instance_list = add_tree(tree);
-    
+
     int num_instances = other_instance_list.get_num_instances();
     for (int i = 0; i < num_instances; ++i) {
       CPT(TransformState) other_trans = other_instance_list.get_instance(i);
@@ -388,8 +388,8 @@ add_instances_from(const SpeedTreeNode *other, const TransformState *transform)
 //               slope_min and slope_max are ignored.
 ////////////////////////////////////////////////////////////////////
 void SpeedTreeNode::
-add_random_instances(const STTree *tree, int quantity, 
-                     PN_stdfloat x_min, PN_stdfloat x_max, 
+add_random_instances(const STTree *tree, int quantity,
+                     PN_stdfloat x_min, PN_stdfloat x_max,
                      PN_stdfloat y_min, PN_stdfloat y_max,
                      PN_stdfloat scale_min, PN_stdfloat scale_max,
                      PN_stdfloat height_min, PN_stdfloat height_max,
@@ -417,7 +417,7 @@ add_random_instances(const STTree *tree, int quantity,
         }
       }
       transform._pos[2] = _terrain->get_height(transform._pos[0], transform._pos[1]);
-      
+
     } else {
       // No terrain; just pick a random height.
       transform._pos[2] = randomizer.random_real(height_max - height_min) + height_min;
@@ -484,7 +484,7 @@ add_from_stf(const Filename &stf_filename, const LoaderOptions &options) {
 //               NULL, the default global Loader is used instead.
 ////////////////////////////////////////////////////////////////////
 bool SpeedTreeNode::
-add_from_stf(istream &in, const Filename &pathname, 
+add_from_stf(istream &in, const Filename &pathname,
              const LoaderOptions &options, Loader *loader) {
   if (loader == NULL) {
     loader = Loader::get_global_ptr();
@@ -701,7 +701,7 @@ reload_config() {
   int num_shadow_maps = speedtree_cascading_shadow_splits.get_num_words();
   if (num_shadow_maps > SpeedTree::c_nMaxNumShadowMaps) {
     speedtree_cat.warning()
-      << "SpeedTree is current compiled to support a maximum of " 
+      << "SpeedTree is current compiled to support a maximum of "
       << SpeedTree::c_nMaxNumShadowMaps << " shadow maps.\n";
     num_shadow_maps = SpeedTree::c_nMaxNumShadowMaps;
   }
@@ -747,7 +747,7 @@ reload_config() {
   _forest_render.SetRenderInfo(render_info);
 
   _terrain_render.SetMaxAnisotropy(speedtree_max_anisotropy);
-  _terrain_render.SetHint(SpeedTree::CTerrain::HINT_MAX_NUM_VISIBLE_CELLS, 
+  _terrain_render.SetHint(SpeedTree::CTerrain::HINT_MAX_NUM_VISIBLE_CELLS,
                           speedtree_max_num_visible_cells);
   _visible_terrain.Reserve(speedtree_max_num_visible_cells);
 
@@ -787,12 +787,12 @@ authorize(const string &license) {
         SpeedTree::CCore::Authorize(speedtree_license.c_str());
       }
     }
-                                                             
+
     _authorized = SpeedTree::CCore::IsAuthorized();
 
     SpeedTree::CCore::SetTextureFlip(true);
   }
-  
+
   return _authorized;
 }
 
@@ -821,7 +821,7 @@ SpeedTreeNode(const SpeedTreeNode &copy) :
 
   // No way to copy these parameters, so we just re-assign them.
   _terrain_render.SetMaxAnisotropy(speedtree_max_anisotropy);
-  _terrain_render.SetHint(SpeedTree::CTerrain::HINT_MAX_NUM_VISIBLE_CELLS, 
+  _terrain_render.SetHint(SpeedTree::CTerrain::HINT_MAX_NUM_VISIBLE_CELLS,
                           speedtree_max_num_visible_cells);
   _visible_terrain.Reserve(speedtree_max_num_visible_cells);
 
@@ -848,7 +848,7 @@ SpeedTreeNode(const SpeedTreeNode &copy) :
 ////////////////////////////////////////////////////////////////////
 //     Function: SpeedTreeNode::Destructor
 //       Access: Published, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 SpeedTreeNode::
 ~SpeedTreeNode() {
@@ -980,7 +980,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
   ClockObject *clock = ClockObject::get_global_clock();
   _forest_render.SetGlobalTime(clock->get_frame_time() + _time_delta + _global_time_delta);
   _forest_render.AdvanceGlobalWind();
-  
+
   // Compute the modelview and camera transforms, to pass to the
   // SpeedTree CView structure.
   CPT(TransformState) orig_modelview = data.get_modelview_transform(trav);
@@ -989,11 +989,11 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
   LMatrix4f modelview_mat = LCAST(float, modelview->get_mat());
   const LPoint3 &camera_pos = camera_transform->get_pos();
   const Lens *lens = trav->get_scene()->get_lens();
-  
+
   LMatrix4f projection_mat =
     LCAST(float, LMatrix4::convert_mat(gsg->get_internal_coordinate_system(), lens->get_coordinate_system()) *
           lens->get_projection_mat());
-  
+
   _view.Set(SpeedTree::Vec3(camera_pos[0], camera_pos[1], camera_pos[2]),
             SpeedTree::Mat4x4(projection_mat.get_data()),
             SpeedTree::Mat4x4(modelview_mat.get_data()),
@@ -1041,7 +1041,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
       }
     }
   }
-    
+
   if (dlight != (DirectionalLight *)NULL) {
     CPT(TransformState) transform = dlight_np.get_transform(trav->get_scene()->get_scene_root().get_parent());
     LVector3 dir = dlight->get_direction() * transform->get_mat();
@@ -1118,11 +1118,9 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) {
     // We create a CullableObject that has an explicit draw_callback
     // into this node, so that we can make the appropriate calls into
     // SpeedTree to render the forest during the actual draw.
-    CullableObject *object = 
+    CullableObject *object =
       new CullableObject(NULL, data._state,
-                         TransformState::make_identity(),
-                         TransformState::make_identity(),
-                         trav->get_scene());
+                         TransformState::make_identity());
     object->set_draw_callback(new DrawCallback(this));
     trav->get_cull_handler()->record_object(object, trav);
   }
@@ -1208,7 +1206,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 //     Function: SpeedTreeNode::write
 //       Access: Public, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 void SpeedTreeNode::
 write(ostream &out, int indent_level) const {
@@ -1219,7 +1217,7 @@ write(ostream &out, int indent_level) const {
   Trees::const_iterator ti;
   for (ti = _trees.begin(); ti != _trees.end(); ++ti) {
     InstanceList *instance_list = (*ti);
-    indent(out, indent_level + 2) 
+    indent(out, indent_level + 2)
       << *instance_list << "\n";
   }
   */
@@ -1254,7 +1252,7 @@ set_transparent_texture_mode(SpeedTree::ETextureAlphaRenderMode eMode) const {
   SpeedTree::CRenderState::SetBlending(false);
   SpeedTree::CRenderState::SetAlphaTesting(false);
   SpeedTree::CRenderState::SetAlphaToCoverage(false);
-  
+
   switch (eMode) {
   case SpeedTree::TRANS_TEXTURE_ALPHA_TESTING:
     SpeedTree::CRenderState::SetAlphaTesting(true);
@@ -1291,7 +1289,7 @@ init_node() {
     return;
   }
 
-  _forest_render.SetHint(SpeedTree::CForest::HINT_MAX_NUM_VISIBLE_CELLS, 
+  _forest_render.SetHint(SpeedTree::CForest::HINT_MAX_NUM_VISIBLE_CELLS,
                          speedtree_max_num_visible_cells);
 
   _forest_render.SetCullCellSize(speedtree_cull_cell_size);
@@ -1354,7 +1352,7 @@ repopulate() {
       write_error(speedtree_cat.warning());
     }
   }
-  
+
   _forest_render.GetPopulationStats(_population_stats);
   print_forest_stats(_population_stats);
 
@@ -1379,8 +1377,8 @@ repopulate() {
   }
 
   _visible_trees.Reserve(_forest_render.GetBaseTrees(),
-                         _forest_render.GetBaseTrees().size(), 
-                         speedtree_max_num_visible_cells, 
+                         _forest_render.GetBaseTrees().size(),
+                         speedtree_max_num_visible_cells,
                          max_instances_by_cell,
                          speedtree_horizontal_billboards);
 }
@@ -1401,8 +1399,8 @@ update_terrain_cells() {
   PN_stdfloat cell_size = _terrain_render.GetCellSize();
 
   // A temporary vertex data object for populating terrain.
-  PT(GeomVertexData) vertex_data = 
-    new GeomVertexData("terrain", _terrain->get_vertex_format(), 
+  PT(GeomVertexData) vertex_data =
+    new GeomVertexData("terrain", _terrain->get_vertex_format(),
                        GeomEnums::UH_static);
   int num_vertices = num_tile_res * num_tile_res;
   vertex_data->set_num_rows(num_vertices);
@@ -1428,7 +1426,7 @@ update_terrain_cells() {
     nassertv(vbo->NumVertices() == num_tile_res * num_tile_res);
     nassertv(vbo->NumVertices() * vbo->VertexSize() == handle->get_data_size_bytes());
     vbo->OverwriteVertices(data_pointer, num_vertices, 0);
-  }    
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1501,12 +1499,12 @@ draw_callback(CallbackData *data) {
       << "Couldn't set view parameters\n";
     write_error(speedtree_cat.warning());
   }
-  
+
   if (has_terrain()) {
     PStatTimer timer1(_draw_speedtree_terrain_pcollector);
     // Is this needed for terrain?
     _terrain_render.UploadShaderConstants
-      (&_forest_render, _light_dir, 
+      (&_forest_render, _light_dir,
        _forest_render.GetRenderInfo().m_sLightMaterial);
 
     // set terrain render states
@@ -1515,14 +1513,14 @@ draw_callback(CallbackData *data) {
     // render actual terrain
     bool terrain = _terrain_render.Render
       (&_forest_render, _visible_terrain, SpeedTree::RENDER_PASS_STANDARD,
-       _light_dir, _forest_render.GetRenderInfo().m_sLightMaterial, 
+       _light_dir, _forest_render.GetRenderInfo().m_sLightMaterial,
        &_forest_render.GetRenderStats());
 
     if (!terrain) {
       speedtree_cat.warning()
         << "Failed to render terrain\n";
       write_error(speedtree_cat.warning());
-      
+
       // Clear the terrain so we don't keep spamming error messages.
       _terrain = NULL;
     }
@@ -1537,7 +1535,7 @@ draw_callback(CallbackData *data) {
     //SpeedTree::ETextureAlphaRenderMode mode = SpeedTree::TRANS_TEXTURE_BLENDING;
     //SpeedTree::ETextureAlphaRenderMode mode = SpeedTree::TRANS_TEXTURE_NOTHING;
     set_transparent_texture_mode(SpeedTree::ETextureAlphaRenderMode(mode));
-    
+
     bool branches = _forest_render.RenderBranches(_visible_trees, SpeedTree::RENDER_PASS_STANDARD);
     bool fronds = _forest_render.RenderFronds(_visible_trees, SpeedTree::RENDER_PASS_STANDARD);
     bool leaf_meshes = _forest_render.RenderLeafMeshes(_visible_trees, SpeedTree::RENDER_PASS_STANDARD);
@@ -1548,7 +1546,7 @@ draw_callback(CallbackData *data) {
     // disabled; but the billboards appear to have been rendered
     // successfully.  Weird.  Just removing this test from the
     // condition.
-    
+
     if (!branches || !fronds || !leaf_meshes || !leaf_cards /* || !billboards */) {
       speedtree_cat.warning()
         << "Failed to render forest completely: "
@@ -1592,27 +1590,27 @@ render_forest_into_shadow_maps() {
   for (int smi = 0; smi < (int)_shadow_infos.size(); ++smi) {
     const SpeedTree::CView &light_view = _shadow_infos[smi]._light_view;
     const SpeedTree::SForestCullResults &light_cull = _shadow_infos[smi]._light_cull;
-    
+
     if (_forest_render.BeginShadowMap(smi, light_view)) {
       success &= _forest_render.UploadViewShaderParameters(light_view);
-      
+
       // branch geometry can be rendered with backfacing triangle
       // removed, so a closer tolerance can be used
       SpeedTree::CRenderState::SetPolygonOffset(1.0f, 0.125f);
-      
+
       success &= _forest_render.RenderBranches(light_cull, SpeedTree::RENDER_PASS_SHADOW);
-      
+
       // the remaining geometry types cannot be backface culled, so we
       // need a much more aggressive offset
       SpeedTree::CRenderState::SetPolygonOffset(10.0f, 1.0f);
-      
+
       success &= _forest_render.RenderFronds(light_cull, SpeedTree::RENDER_PASS_SHADOW);
       success &= _forest_render.RenderLeafMeshes(light_cull, SpeedTree::RENDER_PASS_SHADOW);
       success &= _forest_render.RenderLeafCards(light_cull, SpeedTree::RENDER_PASS_SHADOW, light_view);
-      
+
       // We don't bother to render billboard geometry into the shadow
       // map(s).
-      
+
       success &= _forest_render.EndShadowMap(smi);
     }
   }
@@ -1640,7 +1638,7 @@ setup_for_render(GraphicsStateGuardian *gsg) {
     // This is the first time we have entered the draw callback since
     // creating any SpeedTreeNode.  Now we have an opportunity to do
     // any initial setup that requires a graphics context.
-    
+
 #ifdef SPEEDTREE_OPENGL
     // For OpenGL, we have to ensure GLEW has been initialized.
     // (SpeedTree uses it, though Panda doesn't.)
@@ -1684,7 +1682,7 @@ setup_for_render(GraphicsStateGuardian *gsg) {
       if (instances.empty()) {
         continue;
       }
-      
+
       int max_instances = 2;
       SpeedTree::CMap<const SpeedTree::CTree*, SpeedTree::st_int32>::const_iterator si;
       si = _population_stats.m_mMaxNumInstancesPerCellPerBase.find(tree->get_tree());
@@ -1708,7 +1706,7 @@ setup_for_render(GraphicsStateGuardian *gsg) {
 #endif
       }
 
-      if (!_forest_render.InitTreeGraphics((SpeedTree::CTreeRender *)tree->get_tree(), 
+      if (!_forest_render.InitTreeGraphics((SpeedTree::CTreeRender *)tree->get_tree(),
                                            max_instances, speedtree_horizontal_billboards,
                                            os_textures_dir.c_str())) {
         if (speedtree_cat.is_debug()) {
@@ -1735,7 +1733,7 @@ setup_for_render(GraphicsStateGuardian *gsg) {
 
     if (has_terrain()) {
       // Now initialize the terrain.
-      if (!_terrain_render.Init(speedtree_terrain_num_lods, 
+      if (!_terrain_render.Init(speedtree_terrain_num_lods,
                                 speedtree_terrain_resolution,
                                 speedtree_terrain_cell_size,
                                 _terrain->get_st_vertex_format())) {
@@ -1780,9 +1778,9 @@ cull_forest() {
       SpeedTree::SForestCullResultsRender &light_cull = _shadow_infos[smi]._light_cull;
 
       _forest_render.ComputeLightView
-        (_forest_render.GetLightDir(), _view.GetFrustumPoints(), smi, 
+        (_forest_render.GetLightDir(), _view.GetFrustumPoints(), smi,
          light_view, 0.0f);
-      
+
       light_view.SetLodRefPoint(_view.GetCameraPos());
       _forest_render.CullAndComputeLOD(light_view, light_cull, false);
     }
@@ -1793,7 +1791,7 @@ cull_forest() {
 ////////////////////////////////////////////////////////////////////
 //     Function: SpeedTreeNode::print_forest_stats
 //       Access: Private
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 void SpeedTreeNode::
 print_forest_stats(const SpeedTree::CForest::SPopulationStats &forest_stats) const {
@@ -1894,7 +1892,7 @@ fillin(DatagramIterator &scan, BamReader *manager) {
 ////////////////////////////////////////////////////////////////////
 //     Function: SpeedTreeNode::InstanceList::output
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 void SpeedTreeNode::InstanceList::
 output(ostream &out) const {
@@ -1904,7 +1902,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 //     Function: SpeedTreeNode::InstanceList::write
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 void SpeedTreeNode::InstanceList::
 write(ostream &out, int indent_level) const {