David Rose 15 lat temu
rodzic
commit
4fb98a7f95

+ 12 - 0
panda/src/speedtree/config_speedtree.cxx

@@ -62,6 +62,18 @@ ConfigVariableDouble speedtree_cull_cell_size
 	  "while increasing the number of trees that are rendered "
 	  "while increasing the number of trees that are rendered "
 	  "per call."));
 	  "per call."));
 
 
+ConfigVariableBool speedtree_5_2_stf
+("speedtree-5-2-stf", 
+#if SPEEDTREE_VERSION_MAJOR > 5 || (SPEEDTREE_VERSION_MAJOR == 5 && SPEEDTREE_VERSION_MINOR >= 2)
+ true,
+#else
+ false,
+#endif
+ PRC_DESC("The format of the STF file changed in SpeedTree version 5.2.  "
+	  "Specify true here to read STF files in the new file format, or "
+	  "false to read STF files in the pre-5.2 file format."));
+ 
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: init_libspeedtree
 //     Function: init_libspeedtree
 //  Description: Initializes the library.  This must be called at
 //  Description: Initializes the library.  This must be called at

+ 1 - 0
panda/src/speedtree/config_speedtree.h

@@ -31,6 +31,7 @@ extern ConfigVariableBool speedtree_allow_horizontal_billboards;
 extern ConfigVariableInt speedtree_max_num_visible_cells;
 extern ConfigVariableInt speedtree_max_num_visible_cells;
 extern ConfigVariableInt speedtree_max_billboard_images_by_base;
 extern ConfigVariableInt speedtree_max_billboard_images_by_base;
 extern ConfigVariableDouble speedtree_cull_cell_size;
 extern ConfigVariableDouble speedtree_cull_cell_size;
+extern ConfigVariableBool speedtree_5_2_stf;
 
 
 extern EXPCL_PANDASPEEDTREE void init_libspeedtree();
 extern EXPCL_PANDASPEEDTREE void init_libspeedtree();
 
 

+ 84 - 20
panda/src/speedtree/speedTreeNode.cxx

@@ -26,6 +26,8 @@
 #include "geomDrawCallbackData.h"
 #include "geomDrawCallbackData.h"
 #include "graphicsStateGuardian.h"
 #include "graphicsStateGuardian.h"
 #include "textureAttrib.h"
 #include "textureAttrib.h"
+#include "lightAttrib.h"
+#include "directionalLight.h"
 #include "loader.h"
 #include "loader.h"
 #include "deg_2_rad.h"
 #include "deg_2_rad.h"
 
 
@@ -45,8 +47,13 @@ TypeHandle SpeedTreeNode::DrawCallback::_type_handle;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 SpeedTreeNode::
 SpeedTreeNode::
 SpeedTreeNode(const string &name) :
 SpeedTreeNode(const string &name) :
-  PandaNode(name),
-  _forest(*(new SpeedTree::CForestRender))  // HACK!  SpeedTree doesn't destruct unused CForestRender objects correctly.  Temporarily leaking these things until SpeedTree is fixed.
+  PandaNode(name)
+#ifdef ST_DELETE_FOREST_HACK
+  // Early versions of SpeedTree don't destruct unused CForestRender
+  // objects correctly.  To avoid crashes, we have to leak these
+  // things.
+  , _forest(*(new SpeedTree::CForestRender))
+#endif
 {
 {
   init_node();
   init_node();
   // For now, set an infinite bounding volume.  Maybe in the future
   // For now, set an infinite bounding volume.  Maybe in the future
@@ -373,8 +380,16 @@ add_from_stf(istream &in, const Filename &pathname,
     in >> num_instances;
     in >> num_instances;
     for (int ni = 0; ni < num_instances && in && !in.eof(); ++ni) {
     for (int ni = 0; ni < num_instances && in && !in.eof(); ++ni) {
       LPoint3f pos;
       LPoint3f pos;
-      float rotate, scale, elev_min, elev_max, slope_min, slope_max;
-      in >> pos[0] >> pos[1] >> pos[2] >> rotate >> scale >> elev_min >> elev_max >> slope_min >> slope_max;
+      float rotate, scale;
+      in >> pos[0] >> pos[1] >> pos[2] >> rotate >> scale;
+
+      if (!speedtree_5_2_stf) {
+	// 5.1 or earlier stf files also included these additional
+	// values, which we will ignore:
+	float elev_min, elev_max, slope_min, slope_max;
+	in >> elev_min >> elev_max >> slope_min >> slope_max;
+      }
+
       if (tree != NULL) {
       if (tree != NULL) {
 	add_instance(tree, STTransform(pos, rad_2_deg(rotate), scale));
 	add_instance(tree, STTransform(pos, rad_2_deg(rotate), scale));
       }
       }
@@ -382,11 +397,17 @@ add_from_stf(istream &in, const Filename &pathname,
     in >> os_filename;
     in >> os_filename;
   }
   }
 
 
+  // Consume any whitespace at the end of the file.
+  in >> ws;
+
   if (!in.eof()) {
   if (!in.eof()) {
     // If we didn't read all the way to end-of-file, there was an
     // If we didn't read all the way to end-of-file, there was an
     // error.
     // error.
+    in.clear();
+    string text;
+    in >> text;
     speedtree_cat.error()
     speedtree_cat.error()
-      << "Syntax error in " << pathname << "\n";
+      << "Unexpected text in " << pathname << " at \"" << text << "\"\n";
     return false;
     return false;
   }
   }
 
 
@@ -431,8 +452,13 @@ authorize(const string &license) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 SpeedTreeNode::
 SpeedTreeNode::
 SpeedTreeNode(const SpeedTreeNode &copy) :
 SpeedTreeNode(const SpeedTreeNode &copy) :
-  PandaNode(copy),
-  _forest(*(new SpeedTree::CForestRender))  // HACK!  SpeedTree doesn't destruct unused CForestRender objects correctly.  Temporarily leaking these things until SpeedTree is fixed.
+  PandaNode(copy)
+#ifdef ST_DELETE_FOREST_HACK
+  // Early versions of SpeedTree don't destruct unused CForestRender
+  // objects correctly.  To avoid crashes, we have to leak these
+  // things.
+  , _forest(*(new SpeedTree::CForestRender))
+#endif
 {
 {
   init_node();
   init_node();
 
 
@@ -456,6 +482,17 @@ SpeedTreeNode(const SpeedTreeNode &copy) :
   mark_internal_bounds_stale();
   mark_internal_bounds_stale();
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: SpeedTreeNode::Destructor
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+SpeedTreeNode::
+~SpeedTreeNode() {
+  // Help reduce memory waste from ST_DELETE_FOREST_HACK.
+  _forest.ClearInstances();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: SpeedTreeNode::make_copy
 //     Function: SpeedTreeNode::make_copy
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -527,8 +564,8 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
   
   
   // Compute the modelview and camera transforms, to pass to the
   // Compute the modelview and camera transforms, to pass to the
   // SpeedTree CView structure.
   // SpeedTree CView structure.
-  CPT(TransformState) modelview = data.get_modelview_transform(trav);
-  modelview = gsg->get_cs_transform()->compose(modelview);
+  CPT(TransformState) orig_modelview = data.get_modelview_transform(trav);
+  CPT(TransformState) modelview = gsg->get_cs_transform()->compose(orig_modelview);
   CPT(TransformState) camera_transform = modelview->invert_compose(TransformState::make_identity());
   CPT(TransformState) camera_transform = modelview->invert_compose(TransformState::make_identity());
   const LMatrix4f &modelview_mat = modelview->get_mat();
   const LMatrix4f &modelview_mat = modelview->get_mat();
   const LPoint3f &camera_pos = camera_transform->get_pos();
   const LPoint3f &camera_pos = camera_transform->get_pos();
@@ -543,6 +580,40 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
 	    SpeedTree::Mat4x4(modelview_mat.get_data()),
 	    SpeedTree::Mat4x4(modelview_mat.get_data()),
 	    lens->get_near(), lens->get_far());
 	    lens->get_near(), lens->get_far());
 
 
+  // Convert the render state to SpeedTree's input.
+  const RenderState *state = data._state;
+
+  // Check texture state.  If all textures are disabled, then we ask
+  // SpeedTree to disable textures.
+  bool show_textures = true;
+  const TextureAttrib *ta = DCAST(TextureAttrib, state->get_attrib(TextureAttrib::get_class_slot()));
+  if (ta != (TextureAttrib *)NULL) {
+    show_textures = !ta->has_all_off();
+  }
+  _forest.EnableTexturing(show_textures);
+
+  // Check lighting state.  SpeedTree only supports a single
+  // directional light; we look for a directional light in the
+  // lighting state and pass its direction to SpeedTree.
+  NodePath light;
+  const LightAttrib *la = DCAST(LightAttrib, state->get_attrib(LightAttrib::get_class_slot()));
+  if (la != (LightAttrib *)NULL) {
+    light = la->get_most_important_light();
+  }
+  if (!light.is_empty() && light.node()->is_of_type(DirectionalLight::get_class_type())) {
+    DirectionalLight *light_obj = DCAST(DirectionalLight, light.node());
+
+    CPT(TransformState) transform = light.get_transform(trav->get_scene()->get_scene_root().get_parent());
+    LVector3f dir = light_obj->get_direction() * transform->get_mat();
+    _forest.SetLightDir(SpeedTree::Vec3(dir[0], dir[1], dir[2]));
+
+  } else {
+    // No light.  But there's no way to turn off lighting in
+    // SpeedTree.  In lieu of this, we just shine a light from
+    // above.
+    _forest.SetLightDir(SpeedTree::Vec3(0.0, 0.0, -1.0));
+  }
+
   if (!_needs_repopulate) {
   if (!_needs_repopulate) {
     // Don't bother culling now unless we're correctly fully
     // Don't bother culling now unless we're correctly fully
     // populated.  (Culling won't be accurate unless the forest has
     // populated.  (Culling won't be accurate unless the forest has
@@ -550,7 +621,6 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
     // populate.)
     // populate.)
     _forest.CullAndComputeLOD(_view, _visible_trees);
     _forest.CullAndComputeLOD(_view, _visible_trees);
   }
   }
-  //  cerr << _visible_trees.m_aVisibleCells.size() << " visible cells\n";
 
 
   // Recurse onto the node's children.
   // Recurse onto the node's children.
   return true;
   return true;
@@ -857,16 +927,6 @@ draw_callback(CallbackData *data) {
   GeomDrawCallbackData *geom_cbdata;
   GeomDrawCallbackData *geom_cbdata;
   DCAST_INTO_V(geom_cbdata, data);
   DCAST_INTO_V(geom_cbdata, data);
 
 
-  // Check the input state.
-  const RenderState *state = geom_cbdata->get_object()->_state;
-  
-  bool show_textures = true;
-  const TextureAttrib *texattrib = DCAST(TextureAttrib, state->get_attrib(TextureAttrib::get_class_slot()));
-  if (texattrib != (TextureAttrib *)NULL) {
-    show_textures = !texattrib->has_all_off();
-  }
-  _forest.EnableTexturing(show_textures);
-
   GraphicsStateGuardian *gsg = DCAST(GraphicsStateGuardian, geom_cbdata->get_gsg());
   GraphicsStateGuardian *gsg = DCAST(GraphicsStateGuardian, geom_cbdata->get_gsg());
 
 
   setup_for_render(gsg);
   setup_for_render(gsg);
@@ -889,6 +949,10 @@ draw_callback(CallbackData *data) {
   }
   }
 
 
   _forest.EndRender();
   _forest.EndRender();
+
+  // SpeedTree leaves the graphics state indeterminate.  But this
+  // doesn't help?
+  geom_cbdata->set_lost_state(true);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 15 - 1
panda/src/speedtree/speedTreeNode.h

@@ -27,6 +27,15 @@
 
 
 class Loader;
 class Loader;
 
 
+// There is a SpeedTree bug that prevents reliably deleting a
+// CForestRender object, as of version 5.2.  Presumably it will be
+// fixed beginning in version 5.3.
+#if SPEEDTREE_VERSION_MAJOR > 5 || (SPEEDTREE_VERSION_MAJOR == 5 && SPEEDTREE_VERSION_MINOR >= 3)
+#undef ST_DELETE_FOREST_HACK
+#else
+#define ST_DELETE_FOREST_HACK
+#endif
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : SpeedTreeNode
 //       Class : SpeedTreeNode
 // Description : Interfaces with the SpeedTree library to render
 // Description : Interfaces with the SpeedTree library to render
@@ -68,6 +77,7 @@ PUBLISHED:
 
 
 PUBLISHED:
 PUBLISHED:
   SpeedTreeNode(const string &name);
   SpeedTreeNode(const string &name);
+  virtual ~SpeedTreeNode();
 
 
   INLINE bool is_valid() const;
   INLINE bool is_valid() const;
 
 
@@ -162,7 +172,11 @@ private:
   typedef ov_set<InstanceList *, IndirectLess<InstanceList> > Trees;
   typedef ov_set<InstanceList *, IndirectLess<InstanceList> > Trees;
   Trees _trees;
   Trees _trees;
 
 
-  SpeedTree::CForestRender &_forest;  // Hack!
+#ifdef ST_DELETE_FOREST_HACK
+  SpeedTree::CForestRender &_forest;
+#else
+  SpeedTree::CForestRender _forest;
+#endif  // ST_DELETE_FOREST_HACK
   SpeedTree::CView _view;
   SpeedTree::CView _view;
   SpeedTree::SForestCullResultsRender _visible_trees;
   SpeedTree::SForestCullResultsRender _visible_trees;
   SpeedTree::CForest::SPopulationStats _population_stats;
   SpeedTree::CForest::SPopulationStats _population_stats;