diff --git a/panda/src/parametrics/ropeNode.cxx b/panda/src/parametrics/ropeNode.cxx index d63d4d6cdd..e9bc9bf53b 100644 --- a/panda/src/parametrics/ropeNode.cxx +++ b/panda/src/parametrics/ropeNode.cxx @@ -201,22 +201,10 @@ write(ostream &out, int indent_level) const { // called explicitly when the curve has changed // properties outside of this node's knowledge. //////////////////////////////////////////////////////////////////// -BoundingVolume *RopeNode:: +void RopeNode:: reset_bound(const NodePath &rel_to) { - // First, get ourselves a fresh, empty bounding volume. - BoundingVolume *bound = PandaNode::recompute_internal_bound(); - nassertr(bound != (BoundingVolume *)NULL, bound); - - NurbsCurveEvaluator *curve = get_curve(); - if (curve != (NurbsCurveEvaluator *)NULL) { - pvector verts; - get_curve()->get_vertices(verts, rel_to); - - GeometricBoundingVolume *gbv; - DCAST_INTO_R(gbv, bound, bound); - gbv->around(&verts[0], &verts[verts.size() - 1]); - } - return bound; + do_recompute_bound(rel_to); + changed_internal_bound(); } //////////////////////////////////////////////////////////////////// @@ -229,7 +217,30 @@ reset_bound(const NodePath &rel_to) { //////////////////////////////////////////////////////////////////// BoundingVolume *RopeNode:: recompute_internal_bound() { - return reset_bound(NodePath(this)); + return do_recompute_bound(NodePath(this)); +} + +//////////////////////////////////////////////////////////////////// +// Function: RopeNode::do_recompute_bound +// Access: Private +// Description: Does the actual internal recompute. +//////////////////////////////////////////////////////////////////// +BoundingVolume *RopeNode:: +do_recompute_bound(const NodePath &rel_to) { + // First, get ourselves a fresh, empty bounding volume. + BoundingVolume *bound = PandaNode::recompute_internal_bound(); + nassertr(bound != (BoundingVolume *)NULL, bound); + + NurbsCurveEvaluator *curve = get_curve(); + if (curve != (NurbsCurveEvaluator *)NULL) { + pvector verts; + get_curve()->get_vertices(verts, rel_to); + + GeometricBoundingVolume *gbv; + DCAST_INTO_R(gbv, bound, bound); + gbv->around(&verts[0], &verts[verts.size() - 1]); + } + return bound; } //////////////////////////////////////////////////////////////////// @@ -250,6 +261,7 @@ render_thread(CullTraverser *trav, CullTraverserData &data, NurbsCurveResult *result) { PTA_Vertexf verts; PTA_TexCoordf uvs; + PTA_Colorf colors; PTA_int lengths; int num_verts = get_num_segs() + 1; @@ -264,10 +276,13 @@ render_thread(CullTraverser *trav, CullTraverserData &data, } lengths.push_back(num_verts); } + + colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f)); PT(Geom) geom = new GeomLinestrip; geom->set_num_prims(num_segments); geom->set_coords(verts); + geom->set_colors(colors, G_OVERALL); geom->set_lengths(lengths); CullableObject *object = new CullableObject(geom, data._state, @@ -346,6 +361,7 @@ render_billboard(CullTraverser *trav, CullTraverserData &data, PTA_Vertexf verts; PTA_TexCoordf uvs; + PTA_Colorf colors; PTA_int lengths; int vi = 0; @@ -404,6 +420,8 @@ render_billboard(CullTraverser *trav, CullTraverserData &data, lengths.push_back(length * 2); num_prims++; } + + colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f)); PT(Geom) geom = new GeomTristrip; geom->set_num_prims(num_prims); @@ -411,6 +429,7 @@ render_billboard(CullTraverser *trav, CullTraverserData &data, if (uv_mode != UV_none) { geom->set_texcoords(uvs, G_PER_VERTEX); } + geom->set_colors(colors, G_OVERALL); geom->set_lengths(lengths); CullableObject *object = new CullableObject(geom, data._state, diff --git a/panda/src/parametrics/ropeNode.h b/panda/src/parametrics/ropeNode.h index 17e9b3c5bc..c3a21bc4c4 100644 --- a/panda/src/parametrics/ropeNode.h +++ b/panda/src/parametrics/ropeNode.h @@ -54,13 +54,32 @@ public: PUBLISHED: enum RenderMode { + // Render the rope as a one-pixel thread using a linestrip. RM_thread, + + // Render the rope as a continuous triangle strip oriented to be + // perpendicular to the view vector. RM_billboard }; + enum UVMode { + // Don't generate UV's along the curve. UV_none, + + // Generate UV's based on the parametric coordinates along the + // curve. UV_parametric, + + // Generate UV's in proportion to spatial distance along the + // curve, by using the distance function to compute the length of + // each segment. UV_distance, + + // As above, but don't bother to take the square root of each + // segment. The distance is then in proportion to the + // sum-of-squares of the segments along the rope. If the segments + // are similar in length, this approximates the proportion of + // UV_distance while avoiding hundreds of square root operations. UV_distance2, }; @@ -82,12 +101,13 @@ PUBLISHED: INLINE void set_thickness(float thickness); INLINE float get_thickness() const; - BoundingVolume *reset_bound(const NodePath &rel_to); + void reset_bound(const NodePath &rel_to); protected: virtual BoundingVolume *recompute_internal_bound(); private: + BoundingVolume *do_recompute_bound(const NodePath &rel_to); void render_thread(CullTraverser *trav, CullTraverserData &data, NurbsCurveResult *result); void render_billboard(CullTraverser *trav, CullTraverserData &data, diff --git a/panda/src/pgraph/nodePath.cxx b/panda/src/pgraph/nodePath.cxx index 1e8bac8598..2819c5c7e2 100644 --- a/panda/src/pgraph/nodePath.cxx +++ b/panda/src/pgraph/nodePath.cxx @@ -449,7 +449,7 @@ output(ostream &out) const { if (_head == (NodePathComponent *)NULL) { out << "(empty)"; } else { - r_output(out, _head); + _head->output(out); } } @@ -3042,43 +3042,6 @@ r_get_partial_transform(NodePathComponent *comp, int n) const { } } -//////////////////////////////////////////////////////////////////// -// Function: NodePath::r_output -// Access: Private -// Description: The recursive implementation of output(), this writes -// the names of each node component in order from -// beginning to end, by first walking to the end of the -// linked list and then outputting from there. -//////////////////////////////////////////////////////////////////// -void NodePath:: -r_output(ostream &out, NodePathComponent *comp) const { - PandaNode *node = comp->get_node(); - NodePathComponent *next = comp->get_next(); - if (next != (NodePathComponent *)NULL) { - // This is not the head of the list; keep going up. - r_output(out, next); - out << "/"; - - PandaNode *parent_node = next->get_node(); - if (parent_node->find_stashed(node) >= 0) { - // The node is stashed. - out << "@@"; - - } else if (node->find_parent(parent_node) < 0) { - // Oops, there's an error. This shouldn't happen. - out << ".../"; - } - } - - // Now output this component. - if (node->has_name()) { - out << node->get_name(); - } else { - out << "-" << node->get_type(); - } - // out << "[" << comp->get_length() << "]"; -} - //////////////////////////////////////////////////////////////////// // Function: NodePath::find_matches // Access: Private diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index 49a73e5665..1207e734ee 100644 --- a/panda/src/pgraph/nodePath.h +++ b/panda/src/pgraph/nodePath.h @@ -528,7 +528,6 @@ private: CPT(RenderState) r_get_partial_state(NodePathComponent *comp, int n) const; CPT(TransformState) r_get_net_transform(NodePathComponent *comp) const; CPT(TransformState) r_get_partial_transform(NodePathComponent *comp, int n) const; - void r_output(ostream &out, NodePathComponent *comp) const; void find_matches(NodePathCollection &result, const string &approx_path_str, diff --git a/panda/src/pgraph/nodePathComponent.I b/panda/src/pgraph/nodePathComponent.I index 364a698d32..e2ea614502 100644 --- a/panda/src/pgraph/nodePathComponent.I +++ b/panda/src/pgraph/nodePathComponent.I @@ -135,3 +135,9 @@ get_collapsed() const { CDReader cdata(_cycler); return cdata->_next; } + +INLINE ostream &operator << (ostream &out, const NodePathComponent &comp) { + comp.output(out); + return out; +} + diff --git a/panda/src/pgraph/nodePathComponent.cxx b/panda/src/pgraph/nodePathComponent.cxx index e7a88eaef6..45d5069b11 100644 --- a/panda/src/pgraph/nodePathComponent.cxx +++ b/panda/src/pgraph/nodePathComponent.cxx @@ -162,6 +162,43 @@ uncollapse() { return comp; } +//////////////////////////////////////////////////////////////////// +// Function: NodePathComponent::output +// Access: Public +// Description: The recursive implementation of NodePath::output(), +// this writes the names of each node component in order +// from beginning to end, by first walking to the end of +// the linked list and then outputting from there. +//////////////////////////////////////////////////////////////////// +void NodePathComponent:: +output(ostream &out) const { + PandaNode *node = this->get_node(); + NodePathComponent *next = this->get_next(); + if (next != (NodePathComponent *)NULL) { + // This is not the head of the list; keep going up. + next->output(out); + out << "/"; + + PandaNode *parent_node = next->get_node(); + if (parent_node->find_stashed(node) >= 0) { + // The node is stashed. + out << "@@"; + + } else if (node->find_parent(parent_node) < 0) { + // Oops, there's an error. This shouldn't happen. + out << ".../"; + } + } + + // Now output this component. + if (node->has_name()) { + out << node->get_name(); + } else { + out << "-" << node->get_type(); + } + // out << "[" << this->get_length() << "]"; +} + //////////////////////////////////////////////////////////////////// // Function: NodePathComponent::set_next // Access: Private diff --git a/panda/src/pgraph/nodePathComponent.h b/panda/src/pgraph/nodePathComponent.h index 3c51de1b21..c98668f4a6 100644 --- a/panda/src/pgraph/nodePathComponent.h +++ b/panda/src/pgraph/nodePathComponent.h @@ -64,6 +64,8 @@ public: bool fix_length(); NodePathComponent *uncollapse(); + + void output(ostream &out) const; private: void set_next(NodePathComponent *next); @@ -109,6 +111,8 @@ private: friend class PandaNode; }; +INLINE ostream &operator << (ostream &out, const NodePathComponent &comp); + #include "nodePathComponent.I" #endif diff --git a/panda/src/pgraph/pandaNode.I b/panda/src/pgraph/pandaNode.I index e98d4ebeca..0d336600ff 100644 --- a/panda/src/pgraph/pandaNode.I +++ b/panda/src/pgraph/pandaNode.I @@ -120,6 +120,7 @@ CData() { _transform = TransformState::make_identity(); _draw_mask = DrawMask::all_on(); _net_collide_mask = CollideMask::all_off(); + _fixed_internal_bound = false; } //////////////////////////////////////////////////////////////////// @@ -136,7 +137,8 @@ CData(const PandaNode::CData ©) : _state(copy._state), _effects(copy._effects), _transform(copy._transform), - _draw_mask(copy._draw_mask) + _draw_mask(copy._draw_mask), + _fixed_internal_bound(copy._fixed_internal_bound) { _net_collide_mask = CollideMask::all_off(); } @@ -719,6 +721,8 @@ get_net_collide_mask() const { //////////////////////////////////////////////////////////////////// INLINE void PandaNode:: set_bound(BoundingVolumeType type) { + CDWriter cdata(_cycler); + cdata->_fixed_internal_bound = false; BoundedObject::set_bound(type); } @@ -733,6 +737,8 @@ set_bound(BoundingVolumeType type) { //////////////////////////////////////////////////////////////////// INLINE void PandaNode:: set_bound(const BoundingVolume &volume) { + CDWriter cdata(_cycler); + cdata->_fixed_internal_bound = true; _internal_bound.set_bound(volume); changed_internal_bound(); } @@ -758,7 +764,9 @@ get_bound() const { //////////////////////////////////////////////////////////////////// INLINE const BoundingVolume &PandaNode:: get_internal_bound() const { - if (is_bound_stale() || _internal_bound.is_bound_stale()) { + CDReader cdata(_cycler); + if (!cdata->_fixed_internal_bound && + (is_bound_stale() || _internal_bound.is_bound_stale())) { ((PandaNode *)this)->recompute_internal_bound(); } return _internal_bound.get_bound(); diff --git a/panda/src/pgraph/pandaNode.cxx b/panda/src/pgraph/pandaNode.cxx index 9fde96e31b..9f742b020c 100644 --- a/panda/src/pgraph/pandaNode.cxx +++ b/panda/src/pgraph/pandaNode.cxx @@ -1644,6 +1644,29 @@ get_top_component(PandaNode *child_node, bool force) { //////////////////////////////////////////////////////////////////// PT(NodePathComponent) PandaNode:: get_generic_component(bool accept_ambiguity) { + bool ambiguity_detected = false; + PT(NodePathComponent) result = + r_get_generic_component(accept_ambiguity, ambiguity_detected); + + if (!accept_ambiguity && ambiguity_detected) { + pgraph_cat.warning() + << "Chose: " << *result << "\n"; + nassertr(!unambiguous_graph, result); + } + + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::r_get_generic_component +// Access: Private +// Description: The recursive implementation of +// get_generic_component, this simply sets the flag when +// the ambiguity is detected (so we can report the +// bottom node that started the ambiguous search). +//////////////////////////////////////////////////////////////////// +PT(NodePathComponent) PandaNode:: +r_get_generic_component(bool accept_ambiguity, bool &ambiguity_detected) { int num_parents = get_num_parents(); if (num_parents == 0) { // No parents; no ambiguity. This is the root. @@ -1654,7 +1677,7 @@ get_generic_component(bool accept_ambiguity) { if (num_parents == 1) { // Only one parent; no ambiguity. PT(NodePathComponent) parent = - get_parent(0)->get_generic_component(accept_ambiguity); + get_parent(0)->r_get_generic_component(accept_ambiguity, ambiguity_detected); result = get_component(parent, this); } else { @@ -1664,11 +1687,10 @@ get_generic_component(bool accept_ambiguity) { << *this << " has " << num_parents << " parents; choosing arbitrary path to root.\n"; } - + ambiguity_detected = true; PT(NodePathComponent) parent = - get_parent(0)->get_generic_component(accept_ambiguity); + get_parent(0)->r_get_generic_component(accept_ambiguity, ambiguity_detected); result = get_component(parent, this); - nassertr(accept_ambiguity || !unambiguous_graph, result); } return result; diff --git a/panda/src/pgraph/pandaNode.h b/panda/src/pgraph/pandaNode.h index 70544db046..10a8762040 100644 --- a/panda/src/pgraph/pandaNode.h +++ b/panda/src/pgraph/pandaNode.h @@ -206,6 +206,7 @@ private: static PT(NodePathComponent) get_top_component(PandaNode *child, bool force); PT(NodePathComponent) get_generic_component(bool accept_ambiguity); + PT(NodePathComponent) r_get_generic_component(bool accept_ambiguity, bool &ambiguity_detected); void delete_component(NodePathComponent *component); static void sever_connection(PandaNode *parent_node, PandaNode *child_node); static void new_connection(PandaNode *parent_node, PandaNode *child_node); @@ -292,6 +293,8 @@ private: // updated for the same reasons the bounding volume needs to be // updated. So we update them together. CollideMask _net_collide_mask; + + bool _fixed_internal_bound; }; PipelineCycler _cycler;