From 10242ea0133552bc70d98633184973619b9b6e6b Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 26 Apr 2005 17:51:54 +0000 Subject: [PATCH] new NodePath::set_attrib(), set_clip_plane(), etc. --- panda/src/pgraph/clipPlaneAttrib.I | 130 +++-- panda/src/pgraph/clipPlaneAttrib.cxx | 776 ++++++++++++++++++++------- panda/src/pgraph/clipPlaneAttrib.h | 39 +- panda/src/pgraph/nodePath.I | 143 +++++ panda/src/pgraph/nodePath.cxx | 212 +++++++- panda/src/pgraph/nodePath.h | 23 + 6 files changed, 1052 insertions(+), 271 deletions(-) diff --git a/panda/src/pgraph/clipPlaneAttrib.I b/panda/src/pgraph/clipPlaneAttrib.I index bd9d9b430b..01ab802c1b 100644 --- a/panda/src/pgraph/clipPlaneAttrib.I +++ b/panda/src/pgraph/clipPlaneAttrib.I @@ -19,81 +19,108 @@ //////////////////////////////////////////////////////////////////// // Function: ClipPlaneAttrib::Constructor -// Access: Private +// Access: Protected // Description: Use ClipPlaneAttrib::make() to construct a new // ClipPlaneAttrib object. //////////////////////////////////////////////////////////////////// INLINE ClipPlaneAttrib:: ClipPlaneAttrib() { - _operation = O_set; + _off_all_planes = false; } //////////////////////////////////////////////////////////////////// -// Function: ClipPlaneAttrib::get_operation -// Access: Published -// Description: Returns the basic operation type of the ClipPlaneAttrib. -// If this is O_set, the planes listed here completely -// replace any planes that were already on. If this is -// O_add, the planes here are added to the set of of -// planes that were already on, and if O_remove, the -// planes here are removed from the set of planes that -// were on. +// Function: ClipPlaneAttrib::Copy Constructor +// Access: Protected +// Description: Use ClipPlaneAttrib::make() to construct a new +// ClipPlaneAttrib object. The copy constructor is only +// defined to facilitate methods like add_on_plane(). //////////////////////////////////////////////////////////////////// -INLINE ClipPlaneAttrib::Operation ClipPlaneAttrib:: -get_operation() const { - return _operation; +INLINE ClipPlaneAttrib:: +ClipPlaneAttrib(const ClipPlaneAttrib ©) : + _on_planes(copy._on_planes), + _off_planes(copy._off_planes), + _off_all_planes(copy._off_all_planes) +{ } //////////////////////////////////////////////////////////////////// -// Function: ClipPlaneAttrib::get_num_planes +// Function: ClipPlaneAttrib::get_num_on_planes // Access: Published -// Description: Returns the number of planes listed in the attribute. +// Description: Returns the number of planes that are enabled by +// the attribute. //////////////////////////////////////////////////////////////////// INLINE int ClipPlaneAttrib:: -get_num_planes() const { - return _planes.size(); +get_num_on_planes() const { + return _on_planes.size(); } //////////////////////////////////////////////////////////////////// -// Function: ClipPlaneAttrib::get_plane +// Function: ClipPlaneAttrib::get_on_plane // Access: Published -// Description: Returns the nth planes listed in the attribute. +// Description: Returns the nth plane enabled by the attribute, +// sorted in render order. //////////////////////////////////////////////////////////////////// -INLINE PlaneNode *ClipPlaneAttrib:: -get_plane(int n) const { - nassertr(n >= 0 && n < (int)_planes.size(), (PlaneNode *)NULL); - return _planes[n]; +INLINE NodePath ClipPlaneAttrib:: +get_on_plane(int n) const { + nassertr(n >= 0 && n < (int)_on_planes.size(), NodePath::fail()); + return _on_planes[n]; } //////////////////////////////////////////////////////////////////// -// Function: ClipPlaneAttrib::add_plane +// Function: ClipPlaneAttrib::has_on_plane // Access: Published -// Description: Returns a new ClipPlaneAttrib, just like this one, but -// with the indicated plane added to the list of planes. +// Description: Returns true if the indicated plane is enabled by +// the attrib, false otherwise. //////////////////////////////////////////////////////////////////// -INLINE CPT(RenderAttrib) ClipPlaneAttrib:: -add_plane(PlaneNode *plane) const { - if (_operation == O_remove) { - return compose(make(O_remove, plane)); - } else { - return compose(make(O_add, plane)); - } +INLINE bool ClipPlaneAttrib:: +has_on_plane(const NodePath &plane) const { + return _on_planes.find(plane) != _on_planes.end(); } //////////////////////////////////////////////////////////////////// -// Function: ClipPlaneAttrib::remove_plane +// Function: ClipPlaneAttrib::get_num_off_planes // Access: Published -// Description: Returns a new ClipPlaneAttrib, just like this one, but -// with the indicated plane removed from the list of -// planes. +// Description: Returns the number of planes that are disabled by +// the attribute. //////////////////////////////////////////////////////////////////// -INLINE CPT(RenderAttrib) ClipPlaneAttrib:: -remove_plane(PlaneNode *plane) const { - if (_operation == O_remove) { - return compose(make(O_add, plane)); - } else { - return compose(make(O_remove, plane)); - } +INLINE int ClipPlaneAttrib:: +get_num_off_planes() const { + return _off_planes.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ClipPlaneAttrib::get_off_plane +// Access: Published +// Description: Returns the nth plane disabled by the attribute, +// sorted in arbitrary (pointer) order. +//////////////////////////////////////////////////////////////////// +INLINE NodePath ClipPlaneAttrib:: +get_off_plane(int n) const { + nassertr(n >= 0 && n < (int)_off_planes.size(), NodePath::fail()); + return _off_planes[n]; +} + +//////////////////////////////////////////////////////////////////// +// Function: ClipPlaneAttrib::has_off_plane +// Access: Published +// Description: Returns true if the indicated plane is disabled by +// the attrib, false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool ClipPlaneAttrib:: +has_off_plane(const NodePath &plane) const { + return _off_planes.find(plane) != _off_planes.end() || + (_off_all_planes && !has_on_plane(plane)); +} + +//////////////////////////////////////////////////////////////////// +// Function: ClipPlaneAttrib::has_all_off +// Access: Published +// Description: Returns true if this attrib disables all planes +// (although it may also enable some). +//////////////////////////////////////////////////////////////////// +INLINE bool ClipPlaneAttrib:: +has_all_off() const { + return _off_all_planes; } //////////////////////////////////////////////////////////////////// @@ -104,16 +131,5 @@ remove_plane(PlaneNode *plane) const { //////////////////////////////////////////////////////////////////// INLINE bool ClipPlaneAttrib:: is_identity() const { - return _operation != O_set && _planes.empty(); -} - -//////////////////////////////////////////////////////////////////// -// Function: ClipPlaneAttrib::is_all_off -// Access: Published -// Description: Returns true if this attrib turns off all planes and -// turns none on. -//////////////////////////////////////////////////////////////////// -INLINE bool ClipPlaneAttrib:: -is_all_off() const { - return _operation == O_set && _planes.empty(); + return _on_planes.empty() && _off_planes.empty() && !_off_all_planes; } diff --git a/panda/src/pgraph/clipPlaneAttrib.cxx b/panda/src/pgraph/clipPlaneAttrib.cxx index 913d4aebc5..09b628d890 100644 --- a/panda/src/pgraph/clipPlaneAttrib.cxx +++ b/panda/src/pgraph/clipPlaneAttrib.cxx @@ -24,33 +24,42 @@ #include "datagram.h" #include "datagramIterator.h" +CPT(RenderAttrib) ClipPlaneAttrib::_empty_attrib; +CPT(RenderAttrib) ClipPlaneAttrib::_all_off_attrib; TypeHandle ClipPlaneAttrib::_type_handle; -//////////////////////////////////////////////////////////////////// -// Function: ClipPlaneAttrib::make_all_off -// Access: Published, Static -// Description: Constructs a new ClipPlaneAttrib object that turns off -// all planes (and hence disables planeing). -//////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) ClipPlaneAttrib:: -make_all_off() { - ClipPlaneAttrib *attrib = new ClipPlaneAttrib; - attrib->_operation = O_set; - return return_new(attrib); -} - //////////////////////////////////////////////////////////////////// // Function: ClipPlaneAttrib::make // Access: Published, Static -// Description: Constructs a new ClipPlaneAttrib object that turns on (or -// off, according to op) the indicate plane(s). +// Description: Constructs a new ClipPlaneAttrib object that enables (or +// disables, according to op) the indicated plane(s). +// +// This method is now deprecated. Use add_on_plane() or +// add_off_plane() instead. //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) ClipPlaneAttrib:: make(ClipPlaneAttrib::Operation op, PlaneNode *plane) { - ClipPlaneAttrib *attrib = new ClipPlaneAttrib; - attrib->_operation = op; - attrib->_planes.push_back(plane); - return return_new(attrib); + CPT(RenderAttrib) attrib; + + switch (op) { + case O_set: + attrib = make_all_off(); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane)); + return attrib; + + case O_add: + attrib = make(); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane)); + return attrib; + + case O_remove: + attrib = make(); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane)); + return attrib; + } + + nassertr(false, make()); + return make(); } //////////////////////////////////////////////////////////////////// @@ -58,16 +67,36 @@ make(ClipPlaneAttrib::Operation op, PlaneNode *plane) { // Access: Published, Static // Description: Constructs a new ClipPlaneAttrib object that turns on (or // off, according to op) the indicate plane(s). +// +// This method is now deprecated. Use add_on_plane() or +// add_off_plane() instead. //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) ClipPlaneAttrib:: make(ClipPlaneAttrib::Operation op, PlaneNode *plane1, PlaneNode *plane2) { - ClipPlaneAttrib *attrib = new ClipPlaneAttrib; - attrib->_operation = op; - attrib->_planes.push_back(plane1); - attrib->_planes.push_back(plane2); + CPT(RenderAttrib) attrib; - attrib->_planes.sort(); - return return_new(attrib); + switch (op) { + case O_set: + attrib = make_all_off(); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane1)); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane2)); + return attrib; + + case O_add: + attrib = make(); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane1)); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane2)); + return attrib; + + case O_remove: + attrib = make(); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane1)); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane2)); + return attrib; + } + + nassertr(false, make()); + return make(); } //////////////////////////////////////////////////////////////////// @@ -75,18 +104,40 @@ make(ClipPlaneAttrib::Operation op, PlaneNode *plane1, PlaneNode *plane2) { // Access: Published, Static // Description: Constructs a new ClipPlaneAttrib object that turns on (or // off, according to op) the indicate plane(s). +// +// This method is now deprecated. Use add_on_plane() or +// add_off_plane() instead. //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) ClipPlaneAttrib:: make(ClipPlaneAttrib::Operation op, PlaneNode *plane1, PlaneNode *plane2, PlaneNode *plane3) { - ClipPlaneAttrib *attrib = new ClipPlaneAttrib; - attrib->_operation = op; - attrib->_planes.push_back(plane1); - attrib->_planes.push_back(plane2); - attrib->_planes.push_back(plane3); + CPT(RenderAttrib) attrib; - attrib->_planes.sort(); - return return_new(attrib); + switch (op) { + case O_set: + attrib = make_all_off(); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane1)); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane2)); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane3)); + return attrib; + + case O_add: + attrib = make(); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane1)); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane2)); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane3)); + return attrib; + + case O_remove: + attrib = make(); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane1)); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane2)); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane3)); + return attrib; + } + + nassertr(false, make()); + return make(); } //////////////////////////////////////////////////////////////////// @@ -94,19 +145,110 @@ make(ClipPlaneAttrib::Operation op, PlaneNode *plane1, PlaneNode *plane2, // Access: Published, Static // Description: Constructs a new ClipPlaneAttrib object that turns on (or // off, according to op) the indicate plane(s). +// +// This method is now deprecated. Use add_on_plane() or +// add_off_plane() instead. //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) ClipPlaneAttrib:: make(ClipPlaneAttrib::Operation op, PlaneNode *plane1, PlaneNode *plane2, PlaneNode *plane3, PlaneNode *plane4) { - ClipPlaneAttrib *attrib = new ClipPlaneAttrib; - attrib->_operation = op; - attrib->_planes.push_back(plane1); - attrib->_planes.push_back(plane2); - attrib->_planes.push_back(plane3); - attrib->_planes.push_back(plane4); + CPT(RenderAttrib) attrib; - attrib->_planes.sort(); - return return_new(attrib); + switch (op) { + case O_set: + attrib = make_all_off(); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane1)); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane2)); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane3)); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane4)); + return attrib; + + case O_add: + attrib = make(); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane1)); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane2)); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane3)); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane4)); + return attrib; + + case O_remove: + attrib = make(); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane1)); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane2)); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane3)); + attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane4)); + return attrib; + } + + nassertr(false, make()); + return make(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ClipPlaneAttrib::get_operation +// Access: Published +// Description: Returns the basic operation type of the ClipPlaneAttrib. +// If this is O_set, the planes listed here completely +// replace any planes that were already on. If this is +// O_add, the planes here are added to the set of of +// planes that were already on, and if O_remove, the +// planes here are removed from the set of planes that +// were on. +// +// This method is now deprecated. ClipPlaneAttribs +// nowadays have a separate list of on_planes and +// off_planes, so this method doesn't make sense. Query +// the lists independently. +//////////////////////////////////////////////////////////////////// +ClipPlaneAttrib::Operation ClipPlaneAttrib:: +get_operation() const { + if (has_all_off()) { + return O_set; + + } else if (get_num_off_planes() == 0) { + return O_add; + + } else { + return O_remove; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ClipPlaneAttrib::get_num_planes +// Access: Published +// Description: Returns the number of planes listed in the attribute. +// +// This method is now deprecated. ClipPlaneAttribs +// nowadays have a separate list of on_planes and +// off_planes, so this method doesn't make sense. Query +// the lists independently. +//////////////////////////////////////////////////////////////////// +int ClipPlaneAttrib:: +get_num_planes() const { + if (get_num_off_planes() == 0) { + return get_num_on_planes(); + } else { + return get_num_off_planes(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ClipPlaneAttrib::get_plane +// Access: Published +// Description: Returns the nth plane listed in the attribute. +// +// This method is now deprecated. ClipPlaneAttribs +// nowadays have a separate list of on_planes and +// off_planes, so this method doesn't make sense. Query +// the lists independently. +//////////////////////////////////////////////////////////////////// +PlaneNode *ClipPlaneAttrib:: +get_plane(int n) const { + if (get_num_off_planes() == 0) { + return DCAST(PlaneNode, get_on_plane(n).node()); + } else { + return DCAST(PlaneNode, get_off_plane(n).node()); + } } //////////////////////////////////////////////////////////////////// @@ -114,10 +256,164 @@ make(ClipPlaneAttrib::Operation op, PlaneNode *plane1, PlaneNode *plane2, // Access: Published // Description: Returns true if the indicated plane is listed in the // attrib, false otherwise. +// +// This method is now deprecated. ClipPlaneAttribs +// nowadays have a separate list of on_planes and +// off_planes, so this method doesn't make sense. Query +// the lists independently. //////////////////////////////////////////////////////////////////// bool ClipPlaneAttrib:: has_plane(PlaneNode *plane) const { - return _planes.find(plane) != _planes.end(); + if (get_num_off_planes() == 0) { + return has_on_plane(NodePath(plane)); + } else { + return has_off_plane(NodePath(plane)); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ClipPlaneAttrib::add_plane +// Access: Published +// Description: Returns a new ClipPlaneAttrib, just like this one, but +// with the indicated plane added to the list of planes. +// +// This method is now deprecated. Use add_on_plane() or +// add_off_plane() instead. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) ClipPlaneAttrib:: +add_plane(PlaneNode *plane) const { + if (get_num_off_planes() == 0) { + return add_on_plane(NodePath(plane)); + } else { + return add_off_plane(NodePath(plane)); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ClipPlaneAttrib::remove_plane +// Access: Published +// Description: Returns a new ClipPlaneAttrib, just like this one, but +// with the indicated plane removed from the list of +// planes. +// +// This method is now deprecated. Use remove_on_plane() +// or remove_off_plane() instead. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) ClipPlaneAttrib:: +remove_plane(PlaneNode *plane) const { + if (get_num_off_planes() == 0) { + return remove_on_plane(NodePath(plane)); + } else { + return remove_off_plane(NodePath(plane)); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ClipPlaneAttrib::make +// Access: Published, Static +// Description: Constructs a new ClipPlaneAttrib object that does +// nothing. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) ClipPlaneAttrib:: +make() { + // We make it a special case and store a pointer to the empty attrib + // forever once we find it the first time, as an optimization. + if (_empty_attrib == (RenderAttrib *)NULL) { + _empty_attrib = return_new(new ClipPlaneAttrib); + } + + return _empty_attrib; +} + +//////////////////////////////////////////////////////////////////// +// Function: ClipPlaneAttrib::make_all_off +// Access: Published, Static +// Description: Constructs a new ClipPlaneAttrib object that disables +// all planes (and hence disables clipping). +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) ClipPlaneAttrib:: +make_all_off() { + // We make it a special case and store a pointer to the off attrib + // forever once we find it the first time, as an optimization. + if (_all_off_attrib == (RenderAttrib *)NULL) { + ClipPlaneAttrib *attrib = new ClipPlaneAttrib; + attrib->_off_all_planes = true; + _all_off_attrib = return_new(attrib); + } + + return _all_off_attrib; +} + +//////////////////////////////////////////////////////////////////// +// Function: ClipPlaneAttrib::add_on_plane +// Access: Published +// Description: Returns a new ClipPlaneAttrib, just like this one, but +// with the indicated plane added to the list of planes +// enabled by this attrib. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) ClipPlaneAttrib:: +add_on_plane(const NodePath &plane) const { + nassertr(!plane.is_empty() && plane.node()->is_of_type(PlaneNode::get_class_type()), this); + ClipPlaneAttrib *attrib = new ClipPlaneAttrib(*this); + attrib->_on_planes.insert(plane); + attrib->_off_planes.erase(plane); + + pair insert_result = + attrib->_on_planes.insert(Planes::value_type(plane)); + if (insert_result.second) { + // Also ensure it is removed from the off_planes list. + attrib->_off_planes.erase(plane); + } + + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: ClipPlaneAttrib::remove_on_plane +// Access: Published +// Description: Returns a new ClipPlaneAttrib, just like this one, but +// with the indicated plane removed from the list of +// planes enabled by this attrib. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) ClipPlaneAttrib:: +remove_on_plane(const NodePath &plane) const { + nassertr(!plane.is_empty() && plane.node()->is_of_type(PlaneNode::get_class_type()), this); + ClipPlaneAttrib *attrib = new ClipPlaneAttrib(*this); + attrib->_on_planes.erase(plane); + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: ClipPlaneAttrib::add_off_plane +// Access: Published +// Description: Returns a new ClipPlaneAttrib, just like this one, but +// with the indicated plane added to the list of planes +// disabled by this attrib. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) ClipPlaneAttrib:: +add_off_plane(const NodePath &plane) const { + nassertr(!plane.is_empty() && plane.node()->is_of_type(PlaneNode::get_class_type()), this); + ClipPlaneAttrib *attrib = new ClipPlaneAttrib(*this); + if (!_off_all_planes) { + attrib->_off_planes.insert(plane); + } + attrib->_on_planes.erase(plane); + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: ClipPlaneAttrib::remove_off_plane +// Access: Published +// Description: Returns a new ClipPlaneAttrib, just like this one, but +// with the indicated plane removed from the list of +// planes disabled by this attrib. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) ClipPlaneAttrib:: +remove_off_plane(const NodePath &plane) const { + nassertr(!plane.is_empty() && plane.node()->is_of_type(PlaneNode::get_class_type()), this); + ClipPlaneAttrib *attrib = new ClipPlaneAttrib(*this); + attrib->_off_planes.erase(plane); + return return_new(attrib); } //////////////////////////////////////////////////////////////////// @@ -142,26 +438,38 @@ issue(GraphicsStateGuardianBase *gsg) const { void ClipPlaneAttrib:: output(ostream &out) const { out << get_type() << ":"; - if (_operation == O_set && _planes.empty()) { - out << "all off"; - } else { - switch (_operation) { - case O_set: - out << "set"; - break; - case O_add: - out << "add"; - break; - case O_remove: - out << "remove"; - break; + if (_off_planes.empty()) { + if (_on_planes.empty()) { + if (_off_all_planes) { + out << "all off"; + } else { + out << "identity"; + } + } else { + if (_off_all_planes) { + out << "set"; + } else { + out << "on"; + } } - Planes::const_iterator li; - for (li = _planes.begin(); li != _planes.end(); ++li) { - PlaneNode *plane = (*li); - out << " " << *plane; + } else { + out << "off"; + Planes::const_iterator fi; + for (fi = _off_planes.begin(); fi != _off_planes.end(); ++fi) { + NodePath plane = (*fi); + out << " " << plane; } + + if (!_on_planes.empty()) { + out << " on"; + } + } + + Planes::const_iterator li; + for (li = _on_planes.begin(); li != _on_planes.end(); ++li) { + NodePath plane = (*li); + out << " " << plane; } } @@ -172,10 +480,10 @@ output(ostream &out) const { // types to return a unique number indicating whether // this ClipPlaneAttrib is equivalent to the other one. // -// This should return 0 if the two ClipPlaneAttrib objects -// are equivalent, a number less than zero if this one -// should be sorted before the other one, and a number -// greater than zero otherwise. +// This should return 0 if the two ClipPlaneAttrib +// objects are equivalent, a number less than zero if +// this one should be sorted before the other one, and a +// number greater than zero otherwise. // // This will only be called with two ClipPlaneAttrib // objects whose get_type() functions return the same. @@ -185,29 +493,53 @@ compare_to_impl(const RenderAttrib *other) const { const ClipPlaneAttrib *ta; DCAST_INTO_R(ta, other, 0); - if (_operation != ta->_operation) { - return (int)_operation - (int)ta->_operation; + if (_off_all_planes != ta->_off_all_planes) { + return (int)_off_all_planes - (int)ta->_off_all_planes; } - Planes::const_iterator li = _planes.begin(); - Planes::const_iterator oli = ta->_planes.begin(); + Planes::const_iterator li = _on_planes.begin(); + Planes::const_iterator oli = ta->_on_planes.begin(); - while (li != _planes.end() && oli != ta->_planes.end()) { - PlaneNode *plane = (*li); - PlaneNode *other_plane = (*oli); + while (li != _on_planes.end() && oli != ta->_on_planes.end()) { + NodePath plane = (*li); + NodePath other_plane = (*oli); - if (plane != other_plane) { - return plane < other_plane ? -1 : 1; + int compare = plane.compare_to(other_plane); + if (compare != 0) { + return compare; } ++li; ++oli; } - if (li != _planes.end()) { + if (li != _on_planes.end()) { return 1; } - if (oli != ta->_planes.end()) { + if (oli != ta->_on_planes.end()) { + return -1; + } + + Planes::const_iterator fi = _off_planes.begin(); + Planes::const_iterator ofi = ta->_off_planes.begin(); + + while (fi != _off_planes.end() && ofi != ta->_off_planes.end()) { + NodePath plane = (*fi); + NodePath other_plane = (*ofi); + + int compare = plane.compare_to(other_plane); + if (compare != 0) { + return compare; + } + + ++fi; + ++ofi; + } + + if (fi != _off_planes.end()) { + return 1; + } + if (ofi != ta->_off_planes.end()) { return -1; } @@ -236,29 +568,121 @@ compose_impl(const RenderAttrib *other) const { const ClipPlaneAttrib *ta; DCAST_INTO_R(ta, other, 0); - if (ta->_operation == O_set) { - // If the other type is O_set, it doesn't matter what we are. + if (ta->_off_all_planes) { + // If the other type turns off all planes, it doesn't matter what + // we are. return ta; } - if (_operation == ta->_operation) { - // If the operation types match, the composition is simply the - // union. - return do_add(ta, _operation); + // This is a three-way merge between ai, bi, and ci, except that bi + // and ci should have no intersection and therefore needn't be + // compared to each other. + Planes::const_iterator ai = _on_planes.begin(); + Planes::const_iterator bi = ta->_on_planes.begin(); + Planes::const_iterator ci = ta->_off_planes.begin(); - } else if (ta->_operation == O_remove) { - // If the other operation type is remove, and our type is add or - // set, then remove. - return do_remove(ta, _operation); + // Create a new ClipPlaneAttrib that will hold the result. + ClipPlaneAttrib *new_attrib = new ClipPlaneAttrib; + back_insert_iterator result = + back_inserter(new_attrib->_on_planes); - } else if (_operation == O_remove) { - // If our type is remove, then the other one wins. - return ta; + while (ai != _on_planes.end() && + bi != ta->_on_planes.end() && + ci != ta->_off_planes.end()) { + if ((*ai) < (*bi)) { + if ((*ai) < (*ci)) { + // Here is a plane that we have in the original, which is not + // present in the secondary. + *result = *ai; + ++ai; + ++result; - } else { - // Otherwise, the result is the union. - return do_add(ta, _operation); + } else if ((*ci) < (*ai)) { + // Here is a plane that is disabled in the secondary, but + // was not present in the original. + ++ci; + + } else { // (*ci) == (*ai) + // Here is a plane that is disabled in the secondary, and + // was present in the original. + ++ai; + ++ci; + } + + } else if ((*bi) < (*ai)) { + // Here is a new plane we have in the secondary, that was not + // present in the original. + *result = *bi; + ++bi; + ++result; + + } else { // (*bi) == (*ai) + // Here is a plane we have in both. + *result = *bi; + ++ai; + ++bi; + ++result; + } } + + while (ai != _on_planes.end() && bi != ta->_on_planes.end()) { + if ((*ai) < (*bi)) { + // Here is a plane that we have in the original, which is not + // present in the secondary. + *result = *ai; + ++ai; + ++result; + + } else if ((*bi) < (*ai)) { + // Here is a new plane we have in the secondary, that was not + // present in the original. + *result = *bi; + ++bi; + ++result; + + } else { + // Here is a plane we have in both. + *result = *bi; + ++ai; + ++bi; + ++result; + } + } + + while (ai != _on_planes.end() && ci != ta->_off_planes.end()) { + if ((*ai) < (*ci)) { + // Here is a plane that we have in the original, which is not + // present in the secondary. + *result = *ai; + ++ai; + ++result; + + } else if ((*ci) < (*ai)) { + // Here is a plane that is disabled in the secondary, but + // was not present in the original. + ++ci; + + } else { // (*ci) == (*ai) + // Here is a plane that is disabled in the secondary, and + // was present in the original. + ++ai; + ++ci; + } + } + + while (ai != _on_planes.end()) { + *result = *ai; + ++ai; + ++result; + } + + while (bi != ta->_on_planes.end()) { + *result = *bi; + ++bi; + ++result; + } + + return return_new(new_attrib); } //////////////////////////////////////////////////////////////////// @@ -294,106 +718,6 @@ make_default_impl() const { return new ClipPlaneAttrib; } -//////////////////////////////////////////////////////////////////// -// Function: ClipPlaneAttrib::do_add -// Access: Private -// Description: Returns a new ClipPlaneAttrib that represents all the -// planes of this attrib, with those of the other one -// added in. -//////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) ClipPlaneAttrib:: -do_add(const ClipPlaneAttrib *other, ClipPlaneAttrib::Operation op) const { - Planes::const_iterator ai = _planes.begin(); - Planes::const_iterator bi = other->_planes.begin(); - - // Create a new ClipPlaneAttrib that will hold the result. - ClipPlaneAttrib *new_attrib = new ClipPlaneAttrib; - new_attrib->_operation = op; - back_insert_iterator result = - back_inserter(new_attrib->_planes); - - while (ai != _planes.end() && bi != other->_planes.end()) { - if ((*ai) < (*bi)) { - // Here is a plane that we have in the original, which is not - // present in the secondary. - *result = *ai; - ++ai; - ++result; - } else if ((*bi) < (*ai)) { - // Here is a new plane we have in the secondary, that was not - // present in the original. - *result = *bi; - ++bi; - ++result; - } else { - // Here is a plane we have in both. - *result = *ai; - ++ai; - ++bi; - ++result; - } - } - - while (ai != _planes.end()) { - *result = *ai; - ++ai; - ++result; - } - - while (bi != other->_planes.end()) { - *result = *bi; - ++bi; - ++result; - } - - return return_new(new_attrib); -} - -//////////////////////////////////////////////////////////////////// -// Function: ClipPlaneAttrib::do_remove -// Access: Private -// Description: Returns a new ClipPlaneAttrib that represents all the -// planes of this attrib, with those of the other one -// removed. -//////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) ClipPlaneAttrib:: -do_remove(const ClipPlaneAttrib *other, ClipPlaneAttrib::Operation op) const { - Planes::const_iterator ai = _planes.begin(); - Planes::const_iterator bi = other->_planes.begin(); - - // Create a new ClipPlaneAttrib that will hold the result. - ClipPlaneAttrib *new_attrib = new ClipPlaneAttrib; - new_attrib->_operation = op; - back_insert_iterator result = - back_inserter(new_attrib->_planes); - - while (ai != _planes.end() && bi != other->_planes.end()) { - if ((*ai) < (*bi)) { - // Here is a plane that we have in the original, which is - // not present in the secondary. Keep it. - *result = *ai; - ++ai; - ++result; - } else if ((*bi) < (*ai)) { - // Here is a new plane we have in the secondary, that was - // not present in the original. Ignore it. - ++bi; - } else { - // Here is a plane we have in both. Drop it. - ++ai; - ++bi; - } - } - - while (ai != _planes.end()) { - *result = *ai; - ++ai; - ++result; - } - - return return_new(new_attrib); -} - //////////////////////////////////////////////////////////////////// // Function: ClipPlaneAttrib::register_with_read_factory // Access: Public, Static @@ -415,15 +739,26 @@ void ClipPlaneAttrib:: write_datagram(BamWriter *manager, Datagram &dg) { RenderAttrib::write_datagram(manager, dg); - dg.add_int8((int)_operation); - PN_uint16 num_planes = _planes.size(); - nassertv(num_planes == _planes.size()); - dg.add_uint16(num_planes); + dg.add_bool(_off_all_planes); - Planes::const_iterator li; - for (li = _planes.begin(); li != _planes.end(); ++li) { - PlaneNode *plane = (*li); - manager->write_pointer(dg, plane); + // write the number of off_planes + dg.add_uint16(get_num_off_planes()); + // write the off planes pointers if any + Planes::const_iterator fi; + for (fi = _off_planes.begin(); fi != _off_planes.end(); ++fi) { + NodePath plane = (*fi); + + // Whoops, we don't have a way to write out a NodePath right now. + manager->write_pointer(dg, plane.node()); + } + + // write the number of on planes + dg.add_uint16(get_num_on_planes()); + // write the on planes pointers if any + Planes::const_iterator nti; + for (nti = _on_planes.begin(); nti != _on_planes.end(); ++nti) { + NodePath plane = (*nti); + manager->write_pointer(dg, plane.node()); } } @@ -438,11 +773,22 @@ int ClipPlaneAttrib:: complete_pointers(TypedWritable **p_list, BamReader *manager) { int pi = RenderAttrib::complete_pointers(p_list, manager); - Planes::iterator li; - for (li = _planes.begin(); li != _planes.end(); ++li) { - PlaneNode *node; + Planes::iterator ci = _off_planes.begin(); + while (ci != _off_planes.end()) { + PandaNode *node; DCAST_INTO_R(node, p_list[pi++], pi); - (*li) = node; + NodePath np(node); + (*ci) = np; + ++ci; + } + + ci = _on_planes.begin(); + while (ci != _on_planes.end()) { + PandaNode *node; + DCAST_INTO_R(node, p_list[pi++], pi); + NodePath np(node); + (*ci) = np; + ++ci; } return pi; @@ -479,11 +825,31 @@ void ClipPlaneAttrib:: fillin(DatagramIterator &scan, BamReader *manager) { RenderAttrib::fillin(scan, manager); - _operation = (Operation)scan.get_int8(); - int num_planes = scan.get_uint16(); + // We cheat a little bit here. In the middle of bam version 4.10, + // we completely redefined the bam storage definition for + // ClipPlaneAttribs, without bothering to up the bam version or even to + // attempt to read the old definition. We get away with this, + // knowing that the egg loader doesn't create ClipPlaneAttribs, and + // hence no old bam files have the old definition for ClipPlaneAttrib + // within them. - for (int i = 0; i < num_planes; i++) { + _off_all_planes = scan.get_bool(); + + int num_off_planes = scan.get_uint16(); + + // Push back a NULL pointer for each off Plane for now, until + // we get the actual list of pointers later in complete_pointers(). + _off_planes.reserve(num_off_planes); + int i; + for (i = 0; i < num_off_planes; i++) { manager->read_pointer(scan); - _planes.push_back(NULL); + _off_planes.push_back(NULL); + } + + int num_on_planes = scan.get_uint16(); + _on_planes.reserve(num_on_planes); + for (i = 0; i < num_on_planes; i++) { + manager->read_pointer(scan); + _on_planes.push_back(NULL); } } diff --git a/panda/src/pgraph/clipPlaneAttrib.h b/panda/src/pgraph/clipPlaneAttrib.h index 26fbe115a6..1311c3ca7e 100644 --- a/panda/src/pgraph/clipPlaneAttrib.h +++ b/panda/src/pgraph/clipPlaneAttrib.h @@ -24,6 +24,7 @@ #include "planeNode.h" #include "renderAttrib.h" #include "ordered_vector.h" +#include "nodePath.h" //////////////////////////////////////////////////////////////////// // Class : ClipPlaneAttrib @@ -36,15 +37,19 @@ class EXPCL_PANDA ClipPlaneAttrib : public RenderAttrib { private: INLINE ClipPlaneAttrib(); + INLINE ClipPlaneAttrib(const ClipPlaneAttrib ©); PUBLISHED: + + // This is the old, deprecated interface to ClipPlaneAttrib. Do not + // use any of these methods for new code; these methods will be + // removed soon. enum Operation { O_set, O_add, O_remove }; - static CPT(RenderAttrib) make_all_off(); static CPT(RenderAttrib) make(Operation op, PlaneNode *plane); static CPT(RenderAttrib) make(Operation op, @@ -65,8 +70,27 @@ PUBLISHED: INLINE CPT(RenderAttrib) add_plane(PlaneNode *plane) const; INLINE CPT(RenderAttrib) remove_plane(PlaneNode *plane) const; + + // The following is the new, more general interface to the + // ClipPlaneAttrib. + static CPT(RenderAttrib) make(); + static CPT(RenderAttrib) make_all_off(); + + INLINE int get_num_on_planes() const; + INLINE NodePath get_on_plane(int n) const; + INLINE bool has_on_plane(const NodePath &plane) const; + + INLINE int get_num_off_planes() const; + INLINE NodePath get_off_plane(int n) const; + INLINE bool has_off_plane(const NodePath &plane) const; + INLINE bool has_all_off() const; + INLINE bool is_identity() const; - INLINE bool is_all_off() const; + + CPT(RenderAttrib) add_on_plane(const NodePath &plane) const; + CPT(RenderAttrib) remove_on_plane(const NodePath &plane) const; + CPT(RenderAttrib) add_off_plane(const NodePath &plane) const; + CPT(RenderAttrib) remove_off_plane(const NodePath &plane) const; public: virtual void issue(GraphicsStateGuardianBase *gsg) const; @@ -79,13 +103,12 @@ protected: virtual RenderAttrib *make_default_impl() const; private: - CPT(RenderAttrib) do_add(const ClipPlaneAttrib *other, Operation op) const; - CPT(RenderAttrib) do_remove(const ClipPlaneAttrib *other, Operation op) const; + typedef ov_set Planes; + Planes _on_planes, _off_planes; + bool _off_all_planes; -private: - Operation _operation; - typedef ov_set< PT(PlaneNode) > Planes; - Planes _planes; + static CPT(RenderAttrib) _empty_attrib; + static CPT(RenderAttrib) _all_off_attrib; public: static void register_with_read_factory(); diff --git a/panda/src/pgraph/nodePath.I b/panda/src/pgraph/nodePath.I index 377f9c4a4e..38af5c5115 100644 --- a/panda/src/pgraph/nodePath.I +++ b/panda/src/pgraph/nodePath.I @@ -509,6 +509,149 @@ get_net_state() const { return r_get_net_state(_head); } +//////////////////////////////////////////////////////////////////// +// Function: NodePath::set_attrib +// Access: Published +// Description: Adds the indicated render attribute to the scene +// graph on this node. This attribute will now apply to +// this node and everything below. If there was already +// an attribute of the same type, it is replaced. +//////////////////////////////////////////////////////////////////// +INLINE void NodePath:: +set_attrib(const RenderAttrib *attrib, int priority) { + nassertv_always(!is_empty()); + node()->set_attrib(attrib, priority); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::get_attrib +// Access: Published +// Description: Returns the render attribute of the indicated type, +// if it is defined on the node, or NULL if it is not. +// This checks only what is set on this particular node +// level, and has nothing to do with what render +// attributes may be inherited from parent nodes. +//////////////////////////////////////////////////////////////////// +INLINE const RenderAttrib *NodePath:: +get_attrib(TypeHandle type) const { + nassertr_always(!is_empty(), NULL); + return node()->get_attrib(type); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::has_attrib +// Access: Published +// Description: Returns true if there is a render attribute of the +// indicated type defined on this node, or false if +// there is not. +//////////////////////////////////////////////////////////////////// +INLINE bool NodePath:: +has_attrib(TypeHandle type) const { + nassertr_always(!is_empty(), false); + return node()->has_attrib(type); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::clear_attrib +// Access: Published +// Description: Removes the render attribute of the given type from +// this node. This node, and the subgraph below, will +// now inherit the indicated render attribute from the +// nodes above this one. +//////////////////////////////////////////////////////////////////// +INLINE void NodePath:: +clear_attrib(TypeHandle type) { + nassertv_always(!is_empty()); + node()->clear_attrib(type); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::set_effect +// Access: Published +// Description: Adds the indicated render effect to the scene +// graph on this node. If there was already an effect +// of the same type, it is replaced. +//////////////////////////////////////////////////////////////////// +INLINE void NodePath:: +set_effect(const RenderEffect *effect) { + nassertv_always(!is_empty()); + node()->set_effect(effect); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::get_effect +// Access: Published +// Description: Returns the render effect of the indicated type, +// if it is defined on the node, or NULL if it is not. +//////////////////////////////////////////////////////////////////// +INLINE const RenderEffect *NodePath:: +get_effect(TypeHandle type) const { + nassertr_always(!is_empty(), NULL); + return node()->get_effect(type); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::has_effect +// Access: Published +// Description: Returns true if there is a render effect of the +// indicated type defined on this node, or false if +// there is not. +//////////////////////////////////////////////////////////////////// +INLINE bool NodePath:: +has_effect(TypeHandle type) const { + nassertr_always(!is_empty(), false); + return node()->has_effect(type); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::clear_effect +// Access: Published +// Description: Removes the render effect of the given type from +// this node. +//////////////////////////////////////////////////////////////////// +INLINE void NodePath:: +clear_effect(TypeHandle type) { + nassertv_always(!is_empty()); + node()->clear_effect(type); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::set_effects +// Access: Published +// Description: Sets the complete RenderEffects that will be applied +// this node. This completely replaces whatever has +// been set on this node via repeated calls to +// set_attrib(). +//////////////////////////////////////////////////////////////////// +INLINE void NodePath:: +set_effects(const RenderEffects *effects) { + nassertv_always(!is_empty()); + node()->set_effects(effects); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::get_effects +// Access: Published +// Description: Returns the complete RenderEffects that will be +// applied to this node. +//////////////////////////////////////////////////////////////////// +INLINE const RenderEffects *NodePath:: +get_effects() const { + nassertr_always(!is_empty(), RenderEffects::make_empty()); + return node()->get_effects(); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::clear_effects +// Access: Published +// Description: Resets this node to have no render effects. +//////////////////////////////////////////////////////////////////// +INLINE void NodePath:: +clear_effects() { + nassertv_always(!is_empty()); + node()->clear_effects(); +} + //////////////////////////////////////////////////////////////////// // Function: NodePath::get_transform // Access: Published diff --git a/panda/src/pgraph/nodePath.cxx b/panda/src/pgraph/nodePath.cxx index 04529d65b0..e38c2f59a2 100644 --- a/panda/src/pgraph/nodePath.cxx +++ b/panda/src/pgraph/nodePath.cxx @@ -28,6 +28,7 @@ #include "texMatrixAttrib.h" #include "materialAttrib.h" #include "lightAttrib.h" +#include "clipPlaneAttrib.h" #include "polylightEffect.h" #include "fogAttrib.h" #include "renderModeAttrib.h" @@ -41,6 +42,7 @@ #include "transparencyAttrib.h" #include "antialiasAttrib.h" #include "texProjectorEffect.h" +#include "planeNode.h" #include "lensNode.h" #include "materialPool.h" #include "look_at.h" @@ -2286,7 +2288,7 @@ set_light_off(int priority) { // Function: NodePath::set_light_off // Access: Published // Description: Sets the geometry at this level and below to render -// using without the indicated Light. This is different +// without using the indicated Light. This is different // from not specifying the Light; rather, this // specifically contradicts set_light() at a higher node // level (or, with a priority, overrides a set_light() @@ -2472,6 +2474,214 @@ has_light_off(const NodePath &light) const { return false; } +//////////////////////////////////////////////////////////////////// +// Function: NodePath::set_clip_plane +// Access: Published +// Description: Adds the indicated clipping plane to the list of +// planes that apply to geometry at this node and below. +// The clipping plane itself, a PlaneNode, should be +// parented into the scene graph elsewhere, to represent +// the plane's position in space; but until +// set_clip_plane() is called it will clip no geometry. +//////////////////////////////////////////////////////////////////// +void NodePath:: +set_clip_plane(const NodePath &clip_plane, int priority) { + nassertv_always(!is_empty()); + if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) { + const RenderAttrib *attrib = + node()->get_attrib(ClipPlaneAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + priority = max(priority, + node()->get_state()->get_override(ClipPlaneAttrib::get_class_type())); + const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib); + + // Modify the existing ClipPlaneAttrib to add the indicated + // clip_plane. + node()->set_attrib(la->add_on_plane(clip_plane), priority); + + } else { + // Create a new ClipPlaneAttrib for this node. + CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, ClipPlaneAttrib::make()); + node()->set_attrib(la->add_on_plane(clip_plane), priority); + } + return; + } + nassert_raise("Not a PlaneNode object."); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::set_clip_plane_off +// Access: Published +// Description: Sets the geometry at this level and below to render +// using no clip_planes at all. This is different +// from not specifying a clip_plane; rather, this +// specifically contradicts set_clip_plane() at a higher +// node level (or, with a priority, overrides a +// set_clip_plane() at a lower level). +// +// If no clip_planes are in effect on a particular piece +// of geometry, that geometry is rendered without being +// clipped (other than by the viewing frustum). +//////////////////////////////////////////////////////////////////// +void NodePath:: +set_clip_plane_off(int priority) { + nassertv_always(!is_empty()); + node()->set_attrib(ClipPlaneAttrib::make_all_off(), priority); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::set_clip_plane_off +// Access: Published +// Description: Sets the geometry at this level and below to render +// without being clipped by the indicated PlaneNode. +// This is different from not specifying the PlaneNode; +// rather, this specifically contradicts +// set_clip_plane() at a higher node level (or, with a +// priority, overrides a set_clip_plane() at a lower +// level). +//////////////////////////////////////////////////////////////////// +void NodePath:: +set_clip_plane_off(const NodePath &clip_plane, int priority) { + nassertv_always(!is_empty()); + + if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) { + const RenderAttrib *attrib = + node()->get_attrib(ClipPlaneAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + priority = max(priority, + node()->get_state()->get_override(ClipPlaneAttrib::get_class_type())); + const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib); + + // Modify the existing ClipPlaneAttrib to add the indicated clip_plane + // to the "off" list. This also, incidentally, removes it from + // the "on" list if it is there. + node()->set_attrib(la->add_off_plane(clip_plane), priority); + + } else { + // Create a new ClipPlaneAttrib for this node that turns off the + // indicated clip_plane. + CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, ClipPlaneAttrib::make()); + node()->set_attrib(la->add_off_plane(clip_plane), priority); + } + return; + } + nassert_raise("Not a PlaneNode object."); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::clear_clip_plane +// Access: Published +// Description: Completely removes any clip planes that may have been +// set via set_clip_plane() or set_clip_plane_off() from +// this particular node. +//////////////////////////////////////////////////////////////////// +void NodePath:: +clear_clip_plane() { + nassertv_always(!is_empty()); + node()->clear_attrib(ClipPlaneAttrib::get_class_type()); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::clear_clip_plane +// Access: Published +// Description: Removes any reference to the indicated clipping plane +// from the NodePath. +//////////////////////////////////////////////////////////////////// +void NodePath:: +clear_clip_plane(const NodePath &clip_plane) { + nassertv_always(!is_empty()); + + if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) { + const RenderAttrib *attrib = + node()->get_attrib(ClipPlaneAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, attrib); + la = DCAST(ClipPlaneAttrib, la->remove_on_plane(clip_plane)); + la = DCAST(ClipPlaneAttrib, la->remove_off_plane(clip_plane)); + + if (la->is_identity()) { + node()->clear_attrib(ClipPlaneAttrib::get_class_type()); + + } else { + int priority = node()->get_state()->get_override(ClipPlaneAttrib::get_class_type()); + node()->set_attrib(la, priority); + } + } + return; + } + nassert_raise("Not a PlaneNode object."); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::has_clip_plane +// Access: Published +// Description: Returns true if the indicated clipping plane has been +// specifically applied to this particular node. This +// means that someone called set_clip_plane() on this +// node with the indicated clip_plane. +//////////////////////////////////////////////////////////////////// +bool NodePath:: +has_clip_plane(const NodePath &clip_plane) const { + nassertr_always(!is_empty(), false); + + if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) { + const RenderAttrib *attrib = + node()->get_attrib(ClipPlaneAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib); + return la->has_on_plane(clip_plane); + } + return false; + } + nassert_raise("Not a PlaneNode object."); + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::has_clip_plane_off +// Access: Published +// Description: Returns true if all clipping planes have been +// specifically disabled on this particular node. This +// means that someone called set_clip_plane_off() on +// this node with no parameters. +//////////////////////////////////////////////////////////////////// +bool NodePath:: +has_clip_plane_off() const { + nassertr_always(!is_empty(), false); + + const RenderAttrib *attrib = + node()->get_attrib(ClipPlaneAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib); + return la->has_all_off(); + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::has_clip_plane_off +// Access: Published +// Description: Returns true if the indicated clipping plane has been +// specifically disabled on this particular node. This +// means that someone called set_clip_plane_off() on +// this node with the indicated clip_plane. +//////////////////////////////////////////////////////////////////// +bool NodePath:: +has_clip_plane_off(const NodePath &clip_plane) const { + nassertr_always(!is_empty(), false); + if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) { + const RenderAttrib *attrib = + node()->get_attrib(ClipPlaneAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib); + return la->has_off_plane(clip_plane); + } + } + nassert_raise("Not a PlaneNode object."); + return false; +} + //////////////////////////////////////////////////////////////////// // Function: NodePath::set_bin // Access: Published diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index 61cf8ac4e3..28eb0e7665 100644 --- a/panda/src/pgraph/nodePath.h +++ b/panda/src/pgraph/nodePath.h @@ -246,6 +246,20 @@ PUBLISHED: void set_state(const NodePath &other, const RenderState *state); INLINE CPT(RenderState) get_net_state() const; + INLINE void set_attrib(const RenderAttrib *attrib, int priority = 0); + INLINE const RenderAttrib *get_attrib(TypeHandle type) const; + INLINE bool has_attrib(TypeHandle type) const; + INLINE void clear_attrib(TypeHandle type); + + INLINE void set_effect(const RenderEffect *effect); + INLINE const RenderEffect *get_effect(TypeHandle type) const; + INLINE bool has_effect(TypeHandle type) const; + INLINE void clear_effect(TypeHandle type); + + INLINE void set_effects(const RenderEffects *effects); + INLINE const RenderEffects *get_effects() const; + INLINE void clear_effects(); + INLINE const TransformState *get_transform() const; INLINE void clear_transform(); INLINE void set_transform(const TransformState *transform); @@ -512,6 +526,15 @@ PUBLISHED: bool has_light_off() const; bool has_light_off(const NodePath &light) const; + void set_clip_plane(const NodePath &clip_plane, int priority = 0); + void set_clip_plane_off(int priority = 0); + void set_clip_plane_off(const NodePath &clip_plane, int priority = 0); + void clear_clip_plane(); + void clear_clip_plane(const NodePath &clip_plane); + bool has_clip_plane(const NodePath &clip_plane) const; + bool has_clip_plane_off() const; + bool has_clip_plane_off(const NodePath &clip_plane) const; + void set_bin(const string &bin_name, int draw_order, int priority = 0); void clear_bin(); bool has_bin() const;