mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-20 05:54:54 -04:00
change logic for uniqueness of NodePaths w.r.t. instances
This commit is contained in:
parent
9e0459be64
commit
0b8b4f9cef
@ -108,12 +108,6 @@ private:
|
|||||||
PT(CollisionHandler) _default_handler;
|
PT(CollisionHandler) _default_handler;
|
||||||
TypeHandle _graph_type;
|
TypeHandle _graph_type;
|
||||||
|
|
||||||
// A map of NodePaths is slightly dangerous, since there is a
|
|
||||||
// (small) possiblity that a particular NodePath's sorting order
|
|
||||||
// relative to other NodePaths will spontaneously change. This can
|
|
||||||
// only happen if two NodePaths get collapsed together due to a
|
|
||||||
// removal of a certain kind of instanced node; see the comments in
|
|
||||||
// NodePath.cxx.
|
|
||||||
typedef pmap<NodePath, PT(CollisionHandler) > Colliders;
|
typedef pmap<NodePath, PT(CollisionHandler) > Colliders;
|
||||||
Colliders _colliders;
|
Colliders _colliders;
|
||||||
typedef pvector<NodePath> OrderedColliders;
|
typedef pvector<NodePath> OrderedColliders;
|
||||||
|
@ -112,7 +112,6 @@ NodePath(const NodePath ©) :
|
|||||||
_head(copy._head),
|
_head(copy._head),
|
||||||
_error_type(copy._error_type)
|
_error_type(copy._error_type)
|
||||||
{
|
{
|
||||||
uncollapse_head();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -124,7 +123,6 @@ INLINE void NodePath::
|
|||||||
operator = (const NodePath ©) {
|
operator = (const NodePath ©) {
|
||||||
_head = copy._head;
|
_head = copy._head;
|
||||||
_error_type = copy._error_type;
|
_error_type = copy._error_type;
|
||||||
uncollapse_head();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -212,7 +210,6 @@ get_max_search_depth() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE bool NodePath::
|
INLINE bool NodePath::
|
||||||
is_empty() const {
|
is_empty() const {
|
||||||
uncollapse_head();
|
|
||||||
return (_head == (NodePathComponent *)NULL);
|
return (_head == (NodePathComponent *)NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,7 +221,6 @@ is_empty() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE bool NodePath::
|
INLINE bool NodePath::
|
||||||
is_singleton() const {
|
is_singleton() const {
|
||||||
uncollapse_head();
|
|
||||||
return (_head != (NodePathComponent *)NULL && _head->is_top_node());
|
return (_head != (NodePathComponent *)NULL && _head->is_top_node());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -429,7 +425,6 @@ set_state(const RenderState *state) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE CPT(RenderState) NodePath::
|
INLINE CPT(RenderState) NodePath::
|
||||||
get_net_state() const {
|
get_net_state() const {
|
||||||
uncollapse_head();
|
|
||||||
return r_get_net_state(_head);
|
return r_get_net_state(_head);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,7 +457,6 @@ set_transform(const TransformState *transform) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE CPT(TransformState) NodePath::
|
INLINE CPT(TransformState) NodePath::
|
||||||
get_net_transform() const {
|
get_net_transform() const {
|
||||||
uncollapse_head();
|
|
||||||
return r_get_net_transform(_head);
|
return r_get_net_transform(_head);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -501,7 +495,6 @@ set_prev_transform(const TransformState *transform) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE CPT(TransformState) NodePath::
|
INLINE CPT(TransformState) NodePath::
|
||||||
get_net_prev_transform() const {
|
get_net_prev_transform() const {
|
||||||
uncollapse_head();
|
|
||||||
return r_get_net_prev_transform(_head);
|
return r_get_net_prev_transform(_head);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1149,51 +1142,6 @@ is_hidden(DrawMask camera_mask) const {
|
|||||||
return !get_hidden_ancestor(camera_mask).is_empty();
|
return !get_hidden_ancestor(camera_mask).is_empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: NodePath::unstash
|
|
||||||
// Access: Published
|
|
||||||
// Description: Undoes the effect of a previous stash() on this
|
|
||||||
// node: makes the referenced node (and the entire
|
|
||||||
// subgraph below this node) once again part of the
|
|
||||||
// scene graph. Returns true if the node is unstashed,
|
|
||||||
// or false if it wasn't stashed to begin with.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
INLINE bool NodePath::
|
|
||||||
unstash() {
|
|
||||||
nassertr(!is_singleton(), false);
|
|
||||||
PandaNode *parent_node = get_parent().node();
|
|
||||||
PandaNode *this_node = node();
|
|
||||||
nassertr(parent_node != (PandaNode *)NULL && this_node != (PandaNode *)NULL, false);
|
|
||||||
return parent_node->unstash_child(this_node);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: NodePath::stash
|
|
||||||
// Access: Published
|
|
||||||
// Description: Removes the referenced node (and the entire subgraph
|
|
||||||
// below this node) from the scene graph in any normal
|
|
||||||
// sense. The node will no longer be visible and is not
|
|
||||||
// tested for collisions; furthermore, no normal scene
|
|
||||||
// graph traversal will visit the node. The node's
|
|
||||||
// bounding volume no longer contributes to its parent's
|
|
||||||
// bounding volume.
|
|
||||||
//
|
|
||||||
// A stashed node cannot be located by a normal find()
|
|
||||||
// operation (although a special find string can still
|
|
||||||
// retrieve it).
|
|
||||||
//
|
|
||||||
// Returns true if the node is successfully stashed, or
|
|
||||||
// false if it was already stashed.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
INLINE bool NodePath::
|
|
||||||
stash() {
|
|
||||||
nassertr(!is_singleton(), false);
|
|
||||||
PandaNode *parent_node = get_parent().node();
|
|
||||||
PandaNode *this_node = node();
|
|
||||||
nassertr(parent_node != (PandaNode *)NULL && this_node != (PandaNode *)NULL, false);
|
|
||||||
return parent_node->stash_child(this_node);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: NodePath::is_stashed
|
// Function: NodePath::is_stashed
|
||||||
// Access: Published
|
// Access: Published
|
||||||
@ -1335,6 +1283,28 @@ has_net_tag(const string &key) const {
|
|||||||
return find_net_tag(key).has_tag(key);
|
return find_net_tag(key).has_tag(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: NodePath::set_name
|
||||||
|
// Access: Published
|
||||||
|
// Description: Changes the name of the referenced node.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE void NodePath::
|
||||||
|
set_name(const string &name) {
|
||||||
|
nassertv_always(!is_empty());
|
||||||
|
node()->set_name(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: NodePath::get_name
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the name of the referenced node.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE string NodePath::
|
||||||
|
get_name() const {
|
||||||
|
nassertr_always(!is_empty(), string());
|
||||||
|
return node()->get_name();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
INLINE ostream &operator << (ostream &out, const NodePath &node_path) {
|
INLINE ostream &operator << (ostream &out, const NodePath &node_path) {
|
||||||
node_path.output(out);
|
node_path.output(out);
|
||||||
|
@ -64,7 +64,6 @@ get_num_nodes() const {
|
|||||||
if (is_empty()) {
|
if (is_empty()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
uncollapse_head();
|
|
||||||
return _head->get_length();
|
return _head->get_length();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +79,6 @@ PandaNode *NodePath::
|
|||||||
get_node(int index) const {
|
get_node(int index) const {
|
||||||
nassertr(index >= 0 && index < get_num_nodes(), NULL);
|
nassertr(index >= 0 && index < get_num_nodes(), NULL);
|
||||||
|
|
||||||
uncollapse_head();
|
|
||||||
NodePathComponent *comp = _head;
|
NodePathComponent *comp = _head;
|
||||||
while (index > 0) {
|
while (index > 0) {
|
||||||
// If this assertion fails, the index was out of range; the
|
// If this assertion fails, the index was out of range; the
|
||||||
@ -108,7 +106,6 @@ get_top_node() const {
|
|||||||
return (PandaNode *)NULL;
|
return (PandaNode *)NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
uncollapse_head();
|
|
||||||
NodePathComponent *comp = _head;
|
NodePathComponent *comp = _head;
|
||||||
while (!comp->is_top_node()) {
|
while (!comp->is_top_node()) {
|
||||||
comp = comp->get_next();
|
comp = comp->get_next();
|
||||||
@ -186,9 +183,17 @@ get_sort() const {
|
|||||||
PandaNode *child = node();
|
PandaNode *child = node();
|
||||||
nassertr(parent != (PandaNode *)NULL && child != (PandaNode *)NULL, 0);
|
nassertr(parent != (PandaNode *)NULL && child != (PandaNode *)NULL, 0);
|
||||||
int child_index = parent->find_child(child);
|
int child_index = parent->find_child(child);
|
||||||
nassertr(child_index != -1, 0);
|
if (child_index != -1) {
|
||||||
|
return parent->get_child_sort(child_index);
|
||||||
|
}
|
||||||
|
|
||||||
return parent->get_child_sort(child_index);
|
child_index = parent->find_stashed(child);
|
||||||
|
if (child_index != -1) {
|
||||||
|
return parent->get_stashed_sort(child_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
nassertr(false, 0);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -286,14 +291,12 @@ reparent_to(const NodePath &other, int sort) {
|
|||||||
nassertv(verify_complete());
|
nassertv(verify_complete());
|
||||||
nassertv(other.verify_complete());
|
nassertv(other.verify_complete());
|
||||||
nassertv_always(!is_empty());
|
nassertv_always(!is_empty());
|
||||||
nassertv_always(!other.is_empty());
|
|
||||||
|
|
||||||
uncollapse_head();
|
|
||||||
other.uncollapse_head();
|
|
||||||
PandaNode::reparent(other._head, _head, sort);
|
|
||||||
|
|
||||||
// Reparenting implicitly resents the delta vector.
|
// Reparenting implicitly resents the delta vector.
|
||||||
node()->reset_prev_transform();
|
node()->reset_prev_transform();
|
||||||
|
|
||||||
|
bool reparented = PandaNode::reparent(other._head, _head, sort, false);
|
||||||
|
nassertv(reparented);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -310,7 +313,6 @@ wrt_reparent_to(const NodePath &other, int sort) {
|
|||||||
nassertv(verify_complete());
|
nassertv(verify_complete());
|
||||||
nassertv(other.verify_complete());
|
nassertv(other.verify_complete());
|
||||||
nassertv_always(!is_empty());
|
nassertv_always(!is_empty());
|
||||||
nassertv_always(!other.is_empty());
|
|
||||||
|
|
||||||
if (get_transform() == get_prev_transform()) {
|
if (get_transform() == get_prev_transform()) {
|
||||||
set_transform(get_transform(other));
|
set_transform(get_transform(other));
|
||||||
@ -345,13 +347,17 @@ instance_to(const NodePath &other, int sort) const {
|
|||||||
nassertr(verify_complete(), NodePath::fail());
|
nassertr(verify_complete(), NodePath::fail());
|
||||||
nassertr(other.verify_complete(), NodePath::fail());
|
nassertr(other.verify_complete(), NodePath::fail());
|
||||||
nassertr_always(!is_empty(), NodePath::fail());
|
nassertr_always(!is_empty(), NodePath::fail());
|
||||||
nassertr(!other.is_empty(), NodePath::fail());
|
|
||||||
|
|
||||||
uncollapse_head();
|
|
||||||
other.uncollapse_head();
|
|
||||||
|
|
||||||
NodePath new_instance;
|
NodePath new_instance;
|
||||||
new_instance._head = PandaNode::attach(other._head, node(), sort);
|
|
||||||
|
// First, we'll attach to NULL, to guarantee we get a brand new
|
||||||
|
// instance.
|
||||||
|
new_instance._head = PandaNode::attach(NULL, node(), sort);
|
||||||
|
|
||||||
|
// Now, we'll reparent the new instance to the target node.
|
||||||
|
bool reparented = PandaNode::reparent(other._head, new_instance._head,
|
||||||
|
sort, false);
|
||||||
|
nassertr(reparented, new_instance);
|
||||||
|
|
||||||
// instance_to() doesn't reset the velocity delta, unlike most of
|
// instance_to() doesn't reset the velocity delta, unlike most of
|
||||||
// the other reparenting operations. The reasoning is that
|
// the other reparenting operations. The reasoning is that
|
||||||
@ -414,6 +420,9 @@ copy_to(const NodePath &other, int sort) const {
|
|||||||
// of this NodePath. This is the preferred way to add
|
// of this NodePath. This is the preferred way to add
|
||||||
// nodes to the graph.
|
// nodes to the graph.
|
||||||
//
|
//
|
||||||
|
// If the node was already a child of the parent, this
|
||||||
|
// returns a NodePath to the existing child.
|
||||||
|
//
|
||||||
// This does *not* automatically extend the current
|
// This does *not* automatically extend the current
|
||||||
// NodePath to reflect the attachment; however, a
|
// NodePath to reflect the attachment; however, a
|
||||||
// NodePath that does reflect this extension is
|
// NodePath that does reflect this extension is
|
||||||
@ -425,7 +434,6 @@ attach_new_node(PandaNode *node, int sort) const {
|
|||||||
nassertr_always(!is_empty(), NodePath());
|
nassertr_always(!is_empty(), NodePath());
|
||||||
nassertr(node != (PandaNode *)NULL, NodePath());
|
nassertr(node != (PandaNode *)NULL, NodePath());
|
||||||
|
|
||||||
uncollapse_head();
|
|
||||||
NodePath new_path(*this);
|
NodePath new_path(*this);
|
||||||
new_path._head = PandaNode::attach(_head, node, sort);
|
new_path._head = PandaNode::attach(_head, node, sort);
|
||||||
return new_path;
|
return new_path;
|
||||||
@ -462,7 +470,6 @@ remove_node() {
|
|||||||
// NodePath is clear.
|
// NodePath is clear.
|
||||||
if (!is_empty() && !is_singleton()) {
|
if (!is_empty() && !is_singleton()) {
|
||||||
node()->reset_prev_transform();
|
node()->reset_prev_transform();
|
||||||
uncollapse_head();
|
|
||||||
PandaNode::detach(_head);
|
PandaNode::detach(_head);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,7 +500,6 @@ detach_node() {
|
|||||||
nassertv(_error_type != ET_not_found);
|
nassertv(_error_type != ET_not_found);
|
||||||
if (!is_empty() && !is_singleton()) {
|
if (!is_empty() && !is_singleton()) {
|
||||||
node()->reset_prev_transform();
|
node()->reset_prev_transform();
|
||||||
uncollapse_head();
|
|
||||||
PandaNode::detach(_head);
|
PandaNode::detach(_head);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -506,8 +512,6 @@ detach_node() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void NodePath::
|
void NodePath::
|
||||||
output(ostream &out) const {
|
output(ostream &out) const {
|
||||||
uncollapse_head();
|
|
||||||
|
|
||||||
switch (_error_type) {
|
switch (_error_type) {
|
||||||
case ET_not_found:
|
case ET_not_found:
|
||||||
out << "**not found**";
|
out << "**not found**";
|
||||||
@ -3025,6 +3029,59 @@ get_hidden_ancestor(DrawMask camera_mask) const {
|
|||||||
return not_found();
|
return not_found();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: NodePath::stash
|
||||||
|
// Access: Published
|
||||||
|
// Description: Removes the referenced node (and the entire subgraph
|
||||||
|
// below this node) from the scene graph in any normal
|
||||||
|
// sense. The node will no longer be visible and is not
|
||||||
|
// tested for collisions; furthermore, no normal scene
|
||||||
|
// graph traversal will visit the node. The node's
|
||||||
|
// bounding volume no longer contributes to its parent's
|
||||||
|
// bounding volume.
|
||||||
|
//
|
||||||
|
// A stashed node cannot be located by a normal find()
|
||||||
|
// operation (although a special find string can still
|
||||||
|
// retrieve it).
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void NodePath::
|
||||||
|
stash(int sort) {
|
||||||
|
nassertv_always(!is_singleton() && !is_empty());
|
||||||
|
nassertv(verify_complete());
|
||||||
|
|
||||||
|
bool reparented = PandaNode::reparent(_head->get_next(), _head, sort, true);
|
||||||
|
nassertv(reparented);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: NodePath::unstash
|
||||||
|
// Access: Published
|
||||||
|
// Description: Undoes the effect of a previous stash() on this
|
||||||
|
// node: makes the referenced node (and the entire
|
||||||
|
// subgraph below this node) once again part of the
|
||||||
|
// scene graph.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void NodePath::
|
||||||
|
unstash(int sort) {
|
||||||
|
nassertv_always(!is_singleton() && !is_empty());
|
||||||
|
nassertv(verify_complete());
|
||||||
|
|
||||||
|
bool reparented = PandaNode::reparent(_head->get_next(), _head, sort, false);
|
||||||
|
nassertv(reparented);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: NodePath::unstash_all
|
||||||
|
// Access: Published
|
||||||
|
// Description: Unstashes this node and all stashed child nodes.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void NodePath::
|
||||||
|
unstash_all() {
|
||||||
|
NodePathCollection stashed_descendents = find_all_matches("**/@@*");
|
||||||
|
stashed_descendents.unstash();
|
||||||
|
unstash();
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: NodePath::get_stashed_ancestor
|
// Function: NodePath::get_stashed_ancestor
|
||||||
// Access: Published
|
// Access: Published
|
||||||
@ -3074,9 +3131,6 @@ get_stashed_ancestor() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
int NodePath::
|
int NodePath::
|
||||||
compare_to(const NodePath &other) const {
|
compare_to(const NodePath &other) const {
|
||||||
uncollapse_head();
|
|
||||||
other.uncollapse_head();
|
|
||||||
|
|
||||||
// Nowadays, the NodePathComponents at the head are pointerwise
|
// Nowadays, the NodePathComponents at the head are pointerwise
|
||||||
// equivalent if and only if the NodePaths are equivalent. So we
|
// equivalent if and only if the NodePaths are equivalent. So we
|
||||||
// only have to compare pointers.
|
// only have to compare pointers.
|
||||||
@ -3090,8 +3144,7 @@ compare_to(const NodePath &other) const {
|
|||||||
// Function: NodePath::verify_complete
|
// Function: NodePath::verify_complete
|
||||||
// Access: Published
|
// Access: Published
|
||||||
// Description: Returns true if all of the nodes described in the
|
// Description: Returns true if all of the nodes described in the
|
||||||
// NodePath are connected and the top node is the top
|
// NodePath are connected, or false otherwise.
|
||||||
// of the graph, or false otherwise.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool NodePath::
|
bool NodePath::
|
||||||
verify_complete() const {
|
verify_complete() const {
|
||||||
@ -3099,7 +3152,6 @@ verify_complete() const {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uncollapse_head();
|
|
||||||
const NodePathComponent *comp = _head;
|
const NodePathComponent *comp = _head;
|
||||||
nassertr(comp != (const NodePathComponent *)NULL, false);
|
nassertr(comp != (const NodePathComponent *)NULL, false);
|
||||||
|
|
||||||
@ -3133,15 +3185,7 @@ verify_complete() const {
|
|||||||
length--;
|
length--;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we've reached the top, we should have no parents.
|
return true;
|
||||||
if (length == 0 && node->get_num_parents() == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pgraph_cat.warning()
|
|
||||||
<< *this << " is incomplete; top node " << *node << " indicates length "
|
|
||||||
<< length << " with " << node->get_num_parents() << " parents.\n";
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -3409,22 +3453,6 @@ write_bam_file(const string &filename) const {
|
|||||||
return okflag;
|
return okflag;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: NodePath::uncollapse_head
|
|
||||||
// Access: Private
|
|
||||||
// Description: Quietly and transparently uncollapses the _head
|
|
||||||
// pointer if it needs it. This can happen only when
|
|
||||||
// two distinct NodePaths are collapsed into the same
|
|
||||||
// path after the removal of an instance somewhere
|
|
||||||
// higher up the chain.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
void NodePath::
|
|
||||||
uncollapse_head() const {
|
|
||||||
if (_head != (NodePathComponent *)NULL && _head->is_collapsed()) {
|
|
||||||
((NodePath *)this)->_head = _head->uncollapse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: NodePath::find_common_ancestor
|
// Function: NodePath::find_common_ancestor
|
||||||
// Access: Private, Static
|
// Access: Private, Static
|
||||||
@ -3441,9 +3469,6 @@ NodePathComponent *NodePath::
|
|||||||
find_common_ancestor(const NodePath &a, const NodePath &b,
|
find_common_ancestor(const NodePath &a, const NodePath &b,
|
||||||
int &a_count, int &b_count) {
|
int &a_count, int &b_count) {
|
||||||
nassertr(!a.is_empty() && !b.is_empty(), NULL);
|
nassertr(!a.is_empty() && !b.is_empty(), NULL);
|
||||||
a.uncollapse_head();
|
|
||||||
b.uncollapse_head();
|
|
||||||
|
|
||||||
NodePathComponent *ac = a._head;
|
NodePathComponent *ac = a._head;
|
||||||
NodePathComponent *bc = b._head;
|
NodePathComponent *bc = b._head;
|
||||||
a_count = 0;
|
a_count = 0;
|
||||||
|
@ -552,8 +552,9 @@ PUBLISHED:
|
|||||||
INLINE bool is_hidden(DrawMask camera_mask = DrawMask::all_on()) const;
|
INLINE bool is_hidden(DrawMask camera_mask = DrawMask::all_on()) const;
|
||||||
NodePath get_hidden_ancestor(DrawMask camera_mask = DrawMask::all_on()) const;
|
NodePath get_hidden_ancestor(DrawMask camera_mask = DrawMask::all_on()) const;
|
||||||
|
|
||||||
INLINE bool stash();
|
void stash(int sort = 0);
|
||||||
INLINE bool unstash();
|
void unstash(int sort = 0);
|
||||||
|
void unstash_all();
|
||||||
INLINE bool is_stashed() const;
|
INLINE bool is_stashed() const;
|
||||||
NodePath get_stashed_ancestor() const;
|
NodePath get_stashed_ancestor() const;
|
||||||
|
|
||||||
@ -587,10 +588,12 @@ PUBLISHED:
|
|||||||
INLINE bool has_net_tag(const string &key) const;
|
INLINE bool has_net_tag(const string &key) const;
|
||||||
NodePath find_net_tag(const string &key) const;
|
NodePath find_net_tag(const string &key) const;
|
||||||
|
|
||||||
|
INLINE void set_name(const string &name);
|
||||||
|
INLINE string get_name() const;
|
||||||
|
|
||||||
bool write_bam_file(const string &filename) const;
|
bool write_bam_file(const string &filename) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void uncollapse_head() const;
|
|
||||||
static NodePathComponent *
|
static NodePathComponent *
|
||||||
find_common_ancestor(const NodePath &a, const NodePath &b,
|
find_common_ancestor(const NodePath &a, const NodePath &b,
|
||||||
int &a_count, int &b_count);
|
int &a_count, int &b_count);
|
||||||
|
@ -101,41 +101,10 @@ INLINE NodePathComponent::
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE PandaNode *NodePathComponent::
|
INLINE PandaNode *NodePathComponent::
|
||||||
get_node() const {
|
get_node() const {
|
||||||
// We don't have to bother checking if the component has been
|
|
||||||
// collapsed here, since the _node pointer will still be the same
|
|
||||||
// even if it has.
|
|
||||||
nassertr(_node != (PandaNode *)NULL, _node);
|
nassertr(_node != (PandaNode *)NULL, _node);
|
||||||
return _node;
|
return _node;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: NodePathComponent::is_collapsed
|
|
||||||
// Access: Public
|
|
||||||
// Description: Returns true if this component has been collapsed
|
|
||||||
// with another component. In this case, the component
|
|
||||||
// itself is invalid, and the collapsed component should
|
|
||||||
// be used instead.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
INLINE bool NodePathComponent::
|
|
||||||
is_collapsed() const {
|
|
||||||
CDReader cdata(_cycler);
|
|
||||||
return (cdata->_length == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: NodePathComponent::get_collapsed
|
|
||||||
// Access: Public
|
|
||||||
// Description: If is_collapsed() returns true, this is the component
|
|
||||||
// that this one has been collapsed with, and should be
|
|
||||||
// replaced with.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
INLINE NodePathComponent *NodePathComponent::
|
|
||||||
get_collapsed() const {
|
|
||||||
nassertr(is_collapsed(), (NodePathComponent *)NULL);
|
|
||||||
CDReader cdata(_cycler);
|
|
||||||
return cdata->_next;
|
|
||||||
}
|
|
||||||
|
|
||||||
INLINE ostream &operator << (ostream &out, const NodePathComponent &comp) {
|
INLINE ostream &operator << (ostream &out, const NodePathComponent &comp) {
|
||||||
comp.output(out);
|
comp.output(out);
|
||||||
return out;
|
return out;
|
||||||
|
@ -45,9 +45,6 @@ make_copy() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
int NodePathComponent::
|
int NodePathComponent::
|
||||||
get_key() const {
|
get_key() const {
|
||||||
if (is_collapsed()) {
|
|
||||||
return get_collapsed()->get_key();
|
|
||||||
}
|
|
||||||
if (_key == 0) {
|
if (_key == 0) {
|
||||||
// The first time someone asks for a particular component's key,
|
// The first time someone asks for a particular component's key,
|
||||||
// we make it up on the spot. This helps keep us from wasting
|
// we make it up on the spot. This helps keep us from wasting
|
||||||
@ -67,9 +64,6 @@ get_key() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool NodePathComponent::
|
bool NodePathComponent::
|
||||||
is_top_node() const {
|
is_top_node() const {
|
||||||
if (is_collapsed()) {
|
|
||||||
return get_collapsed()->is_top_node();
|
|
||||||
}
|
|
||||||
CDReader cdata(_cycler);
|
CDReader cdata(_cycler);
|
||||||
return (cdata->_next == (NodePathComponent *)NULL);
|
return (cdata->_next == (NodePathComponent *)NULL);
|
||||||
}
|
}
|
||||||
@ -81,9 +75,6 @@ is_top_node() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
int NodePathComponent::
|
int NodePathComponent::
|
||||||
get_length() const {
|
get_length() const {
|
||||||
if (is_collapsed()) {
|
|
||||||
return get_collapsed()->get_length();
|
|
||||||
}
|
|
||||||
CDReader cdata(_cycler);
|
CDReader cdata(_cycler);
|
||||||
return cdata->_length;
|
return cdata->_length;
|
||||||
}
|
}
|
||||||
@ -95,24 +86,9 @@ get_length() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
NodePathComponent *NodePathComponent::
|
NodePathComponent *NodePathComponent::
|
||||||
get_next() const {
|
get_next() const {
|
||||||
if (is_collapsed()) {
|
|
||||||
return get_collapsed()->get_next();
|
|
||||||
}
|
|
||||||
|
|
||||||
CDReader cdata(_cycler);
|
CDReader cdata(_cycler);
|
||||||
NodePathComponent *next = cdata->_next;
|
NodePathComponent *next = cdata->_next;
|
||||||
|
|
||||||
// If the next component has been collapsed, transparently update
|
|
||||||
// the pointer to get the actual node, and store the new pointer,
|
|
||||||
// before we return. Collapsing can happen at any time to any
|
|
||||||
// component in the path and we have to deal with it.
|
|
||||||
if (next != (NodePathComponent *)NULL && next->is_collapsed()) {
|
|
||||||
next = next->uncollapse();
|
|
||||||
|
|
||||||
CDWriter cdata_w(((NodePathComponent *)this)->_cycler, cdata);
|
|
||||||
cdata_w->_next = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,29 +115,6 @@ fix_length() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: NodePathComponent::uncollapse
|
|
||||||
// Access: Public
|
|
||||||
// Description: Returns this component pointer if the component is
|
|
||||||
// not collapsed; or if it has been collapsed, returns
|
|
||||||
// the pointer it has been collapsed into.
|
|
||||||
//
|
|
||||||
// Collapsing can happen at any time to any component in
|
|
||||||
// the path and we have to deal with it. It happens
|
|
||||||
// when a node is removed further up the path that
|
|
||||||
// results in two instances becoming the same thing.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
NodePathComponent *NodePathComponent::
|
|
||||||
uncollapse() {
|
|
||||||
NodePathComponent *comp = this;
|
|
||||||
|
|
||||||
while (comp->is_collapsed()) {
|
|
||||||
comp = comp->get_collapsed();
|
|
||||||
}
|
|
||||||
|
|
||||||
return comp;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: NodePathComponent::output
|
// Function: NodePathComponent::output
|
||||||
// Access: Public
|
// Access: Public
|
||||||
@ -206,13 +159,9 @@ output(ostream &out) const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void NodePathComponent::
|
void NodePathComponent::
|
||||||
set_next(NodePathComponent *next) {
|
set_next(NodePathComponent *next) {
|
||||||
if (is_collapsed()) {
|
nassertv(next != (NodePathComponent *)NULL);
|
||||||
get_collapsed()->set_next(next);
|
CDWriter cdata(_cycler);
|
||||||
} else {
|
cdata->_next = next;
|
||||||
nassertv(next != (NodePathComponent *)NULL);
|
|
||||||
CDWriter cdata(_cycler);
|
|
||||||
cdata->_next = next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -223,37 +172,6 @@ set_next(NodePathComponent *next) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void NodePathComponent::
|
void NodePathComponent::
|
||||||
set_top_node() {
|
set_top_node() {
|
||||||
if (is_collapsed()) {
|
|
||||||
get_collapsed()->set_top_node();
|
|
||||||
} else {
|
|
||||||
CDWriter cdata(_cycler);
|
|
||||||
cdata->_next = (NodePathComponent *)NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: NodePathComponent::collapse_with
|
|
||||||
// Access: Private
|
|
||||||
// Description: Indicates that this component pointer is no longer
|
|
||||||
// valid, and that the indicated component should be
|
|
||||||
// used instead. This is done whenever two
|
|
||||||
// NodePathComponents have been collapsed together due
|
|
||||||
// to an instance being removed higher up in the graph.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
void NodePathComponent::
|
|
||||||
collapse_with(NodePathComponent *next) {
|
|
||||||
nassertv(!is_collapsed());
|
|
||||||
nassertv(next != (NodePathComponent *)NULL);
|
|
||||||
CDWriter cdata(_cycler);
|
CDWriter cdata(_cycler);
|
||||||
|
cdata->_next = (NodePathComponent *)NULL;
|
||||||
// We indicate a component has been collapsed by setting its length
|
|
||||||
// to zero.
|
|
||||||
cdata->_next = next;
|
|
||||||
cdata->_length = 0;
|
|
||||||
|
|
||||||
if (_key != 0 && next->_key == 0) {
|
|
||||||
// If we had a key set and the other one didn't, it inherits our
|
|
||||||
// key. Otherwise, we inherit the other's key.
|
|
||||||
next->_key = _key;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -56,21 +56,17 @@ public:
|
|||||||
INLINE PandaNode *get_node() const;
|
INLINE PandaNode *get_node() const;
|
||||||
int get_key() const;
|
int get_key() const;
|
||||||
bool is_top_node() const;
|
bool is_top_node() const;
|
||||||
INLINE bool is_collapsed() const;
|
|
||||||
|
|
||||||
NodePathComponent *get_next() const;
|
NodePathComponent *get_next() const;
|
||||||
int get_length() const;
|
int get_length() const;
|
||||||
INLINE NodePathComponent *get_collapsed() const;
|
|
||||||
|
|
||||||
bool fix_length();
|
bool fix_length();
|
||||||
NodePathComponent *uncollapse();
|
|
||||||
|
|
||||||
void output(ostream &out) const;
|
void output(ostream &out) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void set_next(NodePathComponent *next);
|
void set_next(NodePathComponent *next);
|
||||||
void set_top_node();
|
void set_top_node();
|
||||||
void collapse_with(NodePathComponent *next);
|
|
||||||
|
|
||||||
// We don't have to cycle the _node and _key elements, since these
|
// We don't have to cycle the _node and _key elements, since these
|
||||||
// are permanent properties of this object. (Well, the _key is
|
// are permanent properties of this object. (Well, the _key is
|
||||||
|
@ -29,68 +29,15 @@
|
|||||||
|
|
||||||
TypeHandle PandaNode::_type_handle;
|
TypeHandle PandaNode::_type_handle;
|
||||||
|
|
||||||
//
|
|
||||||
// We go through some considerable effort in this class to ensure that
|
|
||||||
// NodePaths are kept consistent as we attach and detach nodes. We
|
|
||||||
// must enforce the following rules:
|
|
||||||
//
|
|
||||||
// 1) Each NodePath (i.e. chain of NodePathComponents) represents a
|
|
||||||
// complete unbroken chain from a PandaNode to the root of the
|
|
||||||
// graph.
|
|
||||||
//
|
|
||||||
// 2) Each NodePathComponent chain is unique. There are no two
|
|
||||||
// different NodePathComponents that reference the same path to the
|
|
||||||
// root.
|
|
||||||
//
|
|
||||||
// The following rules all follow from rules (1) and (2):
|
|
||||||
//
|
|
||||||
// 3) If a PandaNode with no parents is attached to a new parent,
|
|
||||||
// all NodePaths that previously indicated this node as the root of
|
|
||||||
// graph must now be updated to include the complete chain to the
|
|
||||||
// new root.
|
|
||||||
//
|
|
||||||
// 4) If a PandaNode with other parents is attached to a new parent,
|
|
||||||
// any previously existing NodePaths are not affected.
|
|
||||||
//
|
|
||||||
// 5) If a PandaNode is disconnected from its parent, and it has no
|
|
||||||
// other parents, all NodePaths that previously passed through this
|
|
||||||
// node to the old parent must now be updated to indicate this node
|
|
||||||
// is now the root.
|
|
||||||
//
|
|
||||||
// 6) If a PandaNode is disconnected from its parent, and it has at
|
|
||||||
// least one other parent, all NodePaths that previously passed
|
|
||||||
// through this node to the old parent must now be updated to pass
|
|
||||||
// through one of the other parents instead.
|
|
||||||
//
|
|
||||||
// Rules (5) and (6) can especially complicate things because they
|
|
||||||
// introduce the possibility that two formerly distinct NodePaths are
|
|
||||||
// now equivalent, which violates rule (2). For example, if A is the
|
|
||||||
// top of the graph with children B and C, and D is instanced to both
|
|
||||||
// B and C, and E is a child of D, there might be two different
|
|
||||||
// NodePaths to D: A/B/D/E and A/C/D/E. If you then break the
|
|
||||||
// connection between D and E, both NodePaths must now become just the
|
|
||||||
// singleton E.
|
|
||||||
//
|
|
||||||
// Unfortunately, we cannot simply remove one of the extra
|
|
||||||
// NodePathComponents, because there may be any number of NodePath
|
|
||||||
// objects that reference them. Instead, we define the concept of
|
|
||||||
// "collapsed" NodePathComponents, which means one NodePathComponent
|
|
||||||
// can be "collapsed" into a different one so that any attempt to
|
|
||||||
// reference the first actually retrieves the second, rather like a
|
|
||||||
// symbolic link in the file system. When the NodePath traverses its
|
|
||||||
// component chain, it will pass right over the collapsed component in
|
|
||||||
// favor of the one it has been collapsed into.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// There are two different interfaces here for making and breaking
|
// There are two different interfaces here for making and breaking
|
||||||
// parent-child connections: the fundamental PandaNode interface, via
|
// parent-child connections: the fundamental PandaNode interface, via
|
||||||
// add_child() and remove_child() (and related functions), and the
|
// add_child() and remove_child() (and related functions), and the
|
||||||
// NodePath support interface, via attach(), detach(), and reparent().
|
// NodePath support interface, via attach(), detach(), and reparent().
|
||||||
// They both do essentially the same thing, but with slightly
|
// They both do essentially the same thing, but with slightly
|
||||||
// different inputs. Both are responsible for keeping all NodePaths
|
// different inputs. The PandaNode interfaces try to guess which
|
||||||
// up-to-date according to the above rules.
|
// NodePaths should be updated as a result of the scene graph change,
|
||||||
|
// while the NodePath interfaces already know.
|
||||||
//
|
//
|
||||||
// The NodePath support interface functions are strictly called from
|
// The NodePath support interface functions are strictly called from
|
||||||
// within the NodePath class, and are used to implement
|
// within the NodePath class, and are used to implement
|
||||||
@ -1607,7 +1554,15 @@ r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
PT(NodePathComponent) PandaNode::
|
PT(NodePathComponent) PandaNode::
|
||||||
attach(NodePathComponent *parent, PandaNode *child_node, int sort) {
|
attach(NodePathComponent *parent, PandaNode *child_node, int sort) {
|
||||||
nassertr(parent != (NodePathComponent *)NULL, (NodePathComponent *)NULL);
|
if (parent == (NodePathComponent *)NULL) {
|
||||||
|
// Attaching to NULL means to create a new "instance" with no
|
||||||
|
// attachments, and no questions asked.
|
||||||
|
PT(NodePathComponent) child =
|
||||||
|
new NodePathComponent(child_node, (NodePathComponent *)NULL);
|
||||||
|
CDWriter cdata_child(child_node->_cycler);
|
||||||
|
cdata_child->_paths.insert(child);
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
// See if the child was already attached to the parent. If it was,
|
// See if the child was already attached to the parent. If it was,
|
||||||
// we'll use that same NodePathComponent.
|
// we'll use that same NodePathComponent.
|
||||||
@ -1619,7 +1574,7 @@ attach(NodePathComponent *parent, PandaNode *child_node, int sort) {
|
|||||||
child = get_top_component(child_node, true);
|
child = get_top_component(child_node, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
reparent(parent, child, sort);
|
reparent(parent, child, sort, false);
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1688,39 +1643,58 @@ detach(NodePathComponent *child) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: PandaNode::reparent
|
// Function: PandaNode::reparent
|
||||||
// Access: Private, Static
|
// Access: Private, Static
|
||||||
// Description: Switches a node from one parent to another.
|
// Description: Switches a node from one parent to another. Returns
|
||||||
|
// true if the new connection is allowed, or false if it
|
||||||
|
// conflicts with another instance (that is, another
|
||||||
|
// instance of the child is already attached to the
|
||||||
|
// indicated parent).
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void PandaNode::
|
bool PandaNode::
|
||||||
reparent(NodePathComponent *new_parent, NodePathComponent *child, int sort) {
|
reparent(NodePathComponent *new_parent, NodePathComponent *child, int sort,
|
||||||
nassertv(new_parent != (NodePathComponent *)NULL);
|
bool as_stashed) {
|
||||||
nassertv(child != (NodePathComponent *)NULL);
|
nassertr(child != (NodePathComponent *)NULL, false);
|
||||||
|
|
||||||
if (!child->is_top_node()) {
|
if (!child->is_top_node()) {
|
||||||
detach(child);
|
detach(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adjust the NodePathComponents.
|
if (new_parent != (NodePathComponent *)NULL) {
|
||||||
child->set_next(new_parent);
|
PandaNode *child_node = child->get_node();
|
||||||
|
PandaNode *parent_node = new_parent->get_node();
|
||||||
|
|
||||||
PandaNode *child_node = child->get_node();
|
if (child_node->find_parent(parent_node) >= 0) {
|
||||||
PandaNode *parent_node = new_parent->get_node();
|
// Whoops, there's already another instance of the child there.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Now reattach at the indicated sort position.
|
// Redirect the connection to the indicated new parent.
|
||||||
CDWriter cdata_parent(parent_node->_cycler);
|
child->set_next(new_parent);
|
||||||
CDWriter cdata_child(child_node->_cycler);
|
|
||||||
|
// Now reattach the child node at the indicated sort position.
|
||||||
cdata_parent->_down.insert(DownConnection(child_node, sort));
|
CDWriter cdata_parent(parent_node->_cycler);
|
||||||
cdata_child->_up.insert(UpConnection(parent_node));
|
CDWriter cdata_child(child_node->_cycler);
|
||||||
|
|
||||||
cdata_child->_paths.insert(child);
|
|
||||||
child_node->fix_path_lengths(cdata_child);
|
|
||||||
|
|
||||||
// Mark the bounding volumes stale.
|
if (as_stashed) {
|
||||||
parent_node->force_bound_stale();
|
cdata_parent->_stashed.insert(DownConnection(child_node, sort));
|
||||||
|
} else {
|
||||||
|
cdata_parent->_down.insert(DownConnection(child_node, sort));
|
||||||
|
}
|
||||||
|
cdata_child->_up.insert(UpConnection(parent_node));
|
||||||
|
|
||||||
|
cdata_child->_paths.insert(child);
|
||||||
|
child_node->fix_path_lengths(cdata_child);
|
||||||
|
|
||||||
|
// Mark the bounding volumes stale.
|
||||||
|
if (!as_stashed) {
|
||||||
|
parent_node->force_bound_stale();
|
||||||
|
}
|
||||||
|
|
||||||
// Call callback hooks.
|
// Call callback hooks.
|
||||||
parent_node->children_changed();
|
parent_node->children_changed();
|
||||||
child_node->parents_changed();
|
child_node->parents_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -1904,8 +1878,7 @@ delete_component(NodePathComponent *component) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This may legitimately be zero if we are deleting a collapsed NodePath.
|
nassertv(max_num_erased == 1);
|
||||||
// nassertv(max_num_erased == 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -1916,65 +1889,25 @@ delete_component(NodePathComponent *component) {
|
|||||||
// that reflected this connection.
|
// that reflected this connection.
|
||||||
//
|
//
|
||||||
// It severs any NodePathComponents on the child node
|
// It severs any NodePathComponents on the child node
|
||||||
// that reference the indicated parent node. If the
|
// that reference the indicated parent node. These
|
||||||
// child node has additional parents, chooses one of
|
// components remain unattached; there may therefore be
|
||||||
// them arbitrarily instead. Collapses together
|
// multiple "instances" of a node that all have no
|
||||||
// instances below this node that used to differentiate
|
// parent, even while there are other instances that do
|
||||||
// on some instance above the old parent.
|
// have parents.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void PandaNode::
|
void PandaNode::
|
||||||
sever_connection(PandaNode *parent_node, PandaNode *child_node) {
|
sever_connection(PandaNode *parent_node, PandaNode *child_node) {
|
||||||
CDWriter cdata_child(child_node->_cycler);
|
CDWriter cdata_child(child_node->_cycler);
|
||||||
PT(NodePathComponent) collapsed = (NodePathComponent *)NULL;
|
|
||||||
|
|
||||||
Paths::iterator pi;
|
Paths::iterator pi;
|
||||||
pi = cdata_child->_paths.begin();
|
for (pi = cdata_child->_paths.begin();
|
||||||
while (pi != cdata_child->_paths.end()) {
|
pi != cdata_child->_paths.end();
|
||||||
Paths::iterator pnext = pi;
|
++pi) {
|
||||||
++pnext;
|
|
||||||
if (!(*pi)->is_top_node() &&
|
if (!(*pi)->is_top_node() &&
|
||||||
(*pi)->get_next()->get_node() == parent_node) {
|
(*pi)->get_next()->get_node() == parent_node) {
|
||||||
if (collapsed == (NodePathComponent *)NULL) {
|
// Sever the component here.
|
||||||
|
(*pi)->set_top_node();
|
||||||
// This is the first component we've found that references
|
|
||||||
// this node. Should we sever it or reattach it?
|
|
||||||
if (child_node->get_num_parents() == 0) {
|
|
||||||
// If the node no longer has any parents, all of its paths will be
|
|
||||||
// severed here. Collapse them all with the existing top
|
|
||||||
// component if there is one.
|
|
||||||
collapsed = get_top_component(child_node, false);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// If the node still has one parent, all of its paths that
|
|
||||||
// referenced the old parent will be combined with the
|
|
||||||
// remaining parent. If there are multiple parents, choose
|
|
||||||
// the first parent arbitrarily to combine with, and don't
|
|
||||||
// complain if there's ambiguity.
|
|
||||||
collapsed = child_node->get_generic_component(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collapsed == (NodePathComponent *)NULL) {
|
|
||||||
// Sever the component here; there's nothing to attach it
|
|
||||||
// to.
|
|
||||||
(*pi)->set_top_node();
|
|
||||||
collapsed = (*pi);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Collapse the new component with the pre-existing
|
|
||||||
// component.
|
|
||||||
(*pi)->collapse_with(collapsed);
|
|
||||||
cdata_child->_paths.erase(pi);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// This is the second (or later) component we've found that
|
|
||||||
// references this node. We should collapse it with the first
|
|
||||||
// one.
|
|
||||||
(*pi)->collapse_with(collapsed);
|
|
||||||
cdata_child->_paths.erase(pi);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pi = pnext;
|
|
||||||
}
|
}
|
||||||
child_node->fix_path_lengths(cdata_child);
|
child_node->fix_path_lengths(cdata_child);
|
||||||
}
|
}
|
||||||
@ -1983,7 +1916,7 @@ sever_connection(PandaNode *parent_node, PandaNode *child_node) {
|
|||||||
// Function: PandaNode::new_connection
|
// Function: PandaNode::new_connection
|
||||||
// Access: Private, Static
|
// Access: Private, Static
|
||||||
// Description: This is called internally when a parent-child
|
// Description: This is called internally when a parent-child
|
||||||
// connection is establshed to update the
|
// connection is established to update the
|
||||||
// NodePathComponents that might be involved.
|
// NodePathComponents that might be involved.
|
||||||
//
|
//
|
||||||
// It adjusts any NodePathComponents the child has that
|
// It adjusts any NodePathComponents the child has that
|
||||||
|
@ -221,8 +221,8 @@ private:
|
|||||||
static PT(NodePathComponent) attach(NodePathComponent *parent,
|
static PT(NodePathComponent) attach(NodePathComponent *parent,
|
||||||
PandaNode *child, int sort);
|
PandaNode *child, int sort);
|
||||||
static void detach(NodePathComponent *child);
|
static void detach(NodePathComponent *child);
|
||||||
static void reparent(NodePathComponent *new_parent,
|
static bool reparent(NodePathComponent *new_parent,
|
||||||
NodePathComponent *child, int sort);
|
NodePathComponent *child, int sort, bool as_stashed);
|
||||||
static PT(NodePathComponent) get_component(NodePathComponent *parent,
|
static PT(NodePathComponent) get_component(NodePathComponent *parent,
|
||||||
PandaNode *child);
|
PandaNode *child);
|
||||||
static PT(NodePathComponent) get_top_component(PandaNode *child,
|
static PT(NodePathComponent) get_top_component(PandaNode *child,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user