This commit is contained in:
David Rose 2010-10-08 18:41:42 +00:00
parent 1764ae7a7a
commit 4fb98a7f95
4 changed files with 112 additions and 21 deletions

View File

@ -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

View File

@ -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();

View File

@ -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), PandaNode(name)
_forest(*(new SpeedTree::CForestRender)) // HACK! SpeedTree doesn't destruct unused CForestRender objects correctly. Temporarily leaking these things until SpeedTree is fixed. #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; float rotate, scale;
in >> pos[0] >> pos[1] >> pos[2] >> rotate >> scale >> elev_min >> elev_max >> slope_min >> slope_max; 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), PandaNode(copy)
_forest(*(new SpeedTree::CForestRender)) // HACK! SpeedTree doesn't destruct unused CForestRender objects correctly. Temporarily leaking these things until SpeedTree is fixed. #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); CPT(TransformState) orig_modelview = data.get_modelview_transform(trav);
modelview = gsg->get_cs_transform()->compose(modelview); 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);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -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;