From 4fb98a7f954eb1d5a81545d41c51b6f3c0350462 Mon Sep 17 00:00:00 2001 From: David Rose Date: Fri, 8 Oct 2010 18:41:42 +0000 Subject: [PATCH] lighting --- panda/src/speedtree/config_speedtree.cxx | 12 +++ panda/src/speedtree/config_speedtree.h | 1 + panda/src/speedtree/speedTreeNode.cxx | 104 ++++++++++++++++++----- panda/src/speedtree/speedTreeNode.h | 16 +++- 4 files changed, 112 insertions(+), 21 deletions(-) diff --git a/panda/src/speedtree/config_speedtree.cxx b/panda/src/speedtree/config_speedtree.cxx index 8ff124d613..39e7321835 100644 --- a/panda/src/speedtree/config_speedtree.cxx +++ b/panda/src/speedtree/config_speedtree.cxx @@ -62,6 +62,18 @@ ConfigVariableDouble speedtree_cull_cell_size "while increasing the number of trees that are rendered " "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 // Description: Initializes the library. This must be called at diff --git a/panda/src/speedtree/config_speedtree.h b/panda/src/speedtree/config_speedtree.h index 50a995e576..e802d2a5bb 100644 --- a/panda/src/speedtree/config_speedtree.h +++ b/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_billboard_images_by_base; extern ConfigVariableDouble speedtree_cull_cell_size; +extern ConfigVariableBool speedtree_5_2_stf; extern EXPCL_PANDASPEEDTREE void init_libspeedtree(); diff --git a/panda/src/speedtree/speedTreeNode.cxx b/panda/src/speedtree/speedTreeNode.cxx index e429996944..212503e144 100644 --- a/panda/src/speedtree/speedTreeNode.cxx +++ b/panda/src/speedtree/speedTreeNode.cxx @@ -26,6 +26,8 @@ #include "geomDrawCallbackData.h" #include "graphicsStateGuardian.h" #include "textureAttrib.h" +#include "lightAttrib.h" +#include "directionalLight.h" #include "loader.h" #include "deg_2_rad.h" @@ -45,8 +47,13 @@ TypeHandle SpeedTreeNode::DrawCallback::_type_handle; //////////////////////////////////////////////////////////////////// SpeedTreeNode:: 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(); // 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; for (int ni = 0; ni < num_instances && in && !in.eof(); ++ni) { 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) { 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; } + // Consume any whitespace at the end of the file. + in >> ws; + if (!in.eof()) { // If we didn't read all the way to end-of-file, there was an // error. + in.clear(); + string text; + in >> text; speedtree_cat.error() - << "Syntax error in " << pathname << "\n"; + << "Unexpected text in " << pathname << " at \"" << text << "\"\n"; return false; } @@ -431,8 +452,13 @@ authorize(const string &license) { //////////////////////////////////////////////////////////////////// SpeedTreeNode:: SpeedTreeNode(const SpeedTreeNode ©) : - 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(); @@ -456,6 +482,17 @@ SpeedTreeNode(const SpeedTreeNode ©) : 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 // Access: Public, Virtual @@ -527,8 +564,8 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { // Compute the modelview and camera transforms, to pass to the // 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()); const LMatrix4f &modelview_mat = modelview->get_mat(); const LPoint3f &camera_pos = camera_transform->get_pos(); @@ -543,6 +580,40 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { SpeedTree::Mat4x4(modelview_mat.get_data()), 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) { // Don't bother culling now unless we're correctly fully // populated. (Culling won't be accurate unless the forest has @@ -550,7 +621,6 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { // populate.) _forest.CullAndComputeLOD(_view, _visible_trees); } - // cerr << _visible_trees.m_aVisibleCells.size() << " visible cells\n"; // Recurse onto the node's children. return true; @@ -857,16 +927,6 @@ draw_callback(CallbackData *data) { GeomDrawCallbackData *geom_cbdata; 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()); setup_for_render(gsg); @@ -889,6 +949,10 @@ draw_callback(CallbackData *data) { } _forest.EndRender(); + + // SpeedTree leaves the graphics state indeterminate. But this + // doesn't help? + geom_cbdata->set_lost_state(true); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/speedtree/speedTreeNode.h b/panda/src/speedtree/speedTreeNode.h index 3b5c0f7394..949cc10619 100644 --- a/panda/src/speedtree/speedTreeNode.h +++ b/panda/src/speedtree/speedTreeNode.h @@ -27,6 +27,15 @@ 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 // Description : Interfaces with the SpeedTree library to render @@ -68,6 +77,7 @@ PUBLISHED: PUBLISHED: SpeedTreeNode(const string &name); + virtual ~SpeedTreeNode(); INLINE bool is_valid() const; @@ -162,7 +172,11 @@ private: typedef ov_set > 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::SForestCullResultsRender _visible_trees; SpeedTree::CForest::SPopulationStats _population_stats;