| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531 |
- // Filename: wrt.cxx
- // Created by: drose (26Oct98)
- //
- ////////////////////////////////////////////////////////////////////
- #include "wrt.h"
- #include "nodeRelation.h"
- #include "node.h"
- #include "config_graph.h"
- ////////////////////////////////////////////////////////////////////
- // Function: get_cached_net_transition
- // Description: Returns the net transition from the root of the
- // graph, or the nearest ancestor with multiple parents,
- // to and including the indicated arc. This is a
- // support function for wrt() and should not be called
- // directly.
- //
- // This flavor of get_cached_net_transition() gets the
- // transition up to an arc, instead of a node, and does
- // not necessarily start at the root of the scene graph.
- // By starting at the nearest ancestor with multiple
- // parents, we allow ambiguous paths in the scene graph
- // without interfering with state caching. Since there
- // are no nodes with multiple parents in the chain of
- // transitions returned by this function, the result is
- // always unambiguous; any wrt() ambiguity is resolved
- // later.
- ////////////////////////////////////////////////////////////////////
- template<class TransitionWrapper>
- void
- get_cached_net_transition(NodeRelation *arc, Node *&root, UpdateSeq now,
- TransitionWrapper &net, TypeHandle graph_type) {
- TransitionWrapper cur_cache = TransitionWrapper::init_from(net);
- Node *top_subtree = cur_cache.extract_from_cache(arc);
- if (cur_cache.is_cache_verified(now)) {
- // This arc's cached value has recently been verified, so we don't
- // even need to go anywhere--we trust it's still good.
- root = top_subtree;
- net = cur_cache;
- } else {
- // This arc's cache hasn't recently been verified, and we need to
- // verify it now. This will entail at least walking up the scene
- // graph to the root, and possibly recomputing the cache as we go.
- // Get the node above the arc.
- Node *node = arc->get_parent();
- UpRelations::const_iterator uri;
- uri = node->_parents.find(graph_type);
- if (uri == node->_parents.end() || (*uri).second.size() != 1) {
- // The node has zero or multiple parents. It's thus either the
- // top of the scene graph, or it's the first ancestor with
- // multiple parents; in either case, it's as far as we can take
- // the caching. Stop here.
- if (uri == node->_parents.end() || (*uri).second.empty()) {
- // The node is the very top of the scene graph. We'll treat
- // this as a special case by setting the node to NULL. This
- // will tell our calling function that there's no need to look
- // further.
- node = NULL;
- }
- root = node;
- net.extract_from(arc);
- net.set_computed_verified(now);
- net.store_to_cache(arc, node);
- } else {
- // The node has exactly one parent. Carry on.
- NodeRelation *parent = *(*uri).second.begin();
- get_cached_net_transition(parent, root, now, net, graph_type);
- // Now recompute our own cache.
- TransitionWrapper cur_value = TransitionWrapper::init_from(net);
- cur_value.extract_from(arc);
- net.cached_compose(cur_cache, cur_value, now);
- net.store_to_cache(arc, root);
- }
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: get_cached_net_transition
- // Description: Returns the net transition from the root of the graph
- // to the indicated node. This is a support function
- // for wrt() and should not be called directly.
- //
- // If [arc_list_begin..arc_list_end) is nonempty, it
- // contains a list of NodeRelation pointers to resolve
- // ambiguities when a node with multiple parents is
- // encountered.
- ////////////////////////////////////////////////////////////////////
- template<class InputIterator, class TransitionWrapper>
- void
- get_cached_net_transition(const Node *node,
- InputIterator arc_list_begin,
- InputIterator arc_list_end,
- UpdateSeq now,
- TransitionWrapper &result,
- TypeHandle graph_type) {
- if (node == NULL) {
- // the NULL node is by convention equivalent to the root.
- result.make_identity();
- return;
- }
- UpRelations::const_iterator uri;
- uri = node->_parents.find(graph_type);
- if (uri == node->_parents.end()) {
- // This node has no parents. Stop here.
- result.make_identity();
- return;
- }
- const UpRelationPointers &urp = (*uri).second;
- if (urp.empty()) {
- // Again, this node has no parents.
- result.make_identity();
- return;
- }
- const NodeRelation *parent_arc = (const NodeRelation *)NULL;
- if (urp.size() == 1) {
- // There is only one parent, so there's no doubt as to which arc
- // to choose.
- parent_arc = *(urp.begin());
- } else {
- // The node has multiple parents, and we have a list of arcs in
- // arc_list_begin .. arc_list_end. If any of the parents is
- // mentioned in the list, we must choose that parent.
- for (InputIterator ri = arc_list_begin;
- parent_arc == (NodeRelation *)NULL && ri != arc_list_end;
- ++ri) {
- if ((*ri)->get_child() == node) {
- parent_arc = (*ri);
- }
- }
- if (parent_arc == (NodeRelation *)NULL) {
- // No, it wasn't mentioned. Issue a warning and use the first
- // one.
- graph_cat.warning()
- << *node << " has multiple parents; wrt() ambiguous.\n";
- parent_arc = *(urp.begin());
- }
- }
- // Get the net transition leading into this node.
- Node *root;
- get_cached_net_transition((NodeRelation *)parent_arc, root, now, result,
- graph_type);
- if (root != NULL) {
- // There's more to get. The above function call was forced to
- // stop at a node with multiple parents.
- TransitionWrapper more = TransitionWrapper::init_from(result);
- get_cached_net_transition(root, arc_list_begin, arc_list_end,
- now, more, graph_type);
- more.compose_in_place(result);
- result = more;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: get_uncached_net_transition
- // Description: Returns the net transition from the root of the graph
- // to the indicated node. This is a support function
- // for wrt() and should not be called directly.
- //
- // If [arc_list_begin..arc_list_end) is nonempty, it
- // contains a list of NodeRelation pointers to resolve
- // ambiguities when a node with multiple parents is
- // encountered.
- //
- // This variant of get_cached_net_transition() does not
- // respect or update the cache values stored in the
- // arcs. It's intended only as a debugging doublecheck
- // against the normal get_cached_net_transition()
- // function that does do this.
- ////////////////////////////////////////////////////////////////////
- template<class InputIterator, class TransitionWrapper>
- void
- get_uncached_net_transition(const Node *node,
- InputIterator arc_list_begin,
- InputIterator arc_list_end,
- TransitionWrapper &result,
- TypeHandle graph_type) {
- if (node == NULL) {
- // the NULL node is by convention equivalent to the root.
- result.make_identity();
- return;
- }
- UpRelations::const_iterator uri;
- uri = node->_parents.find(graph_type);
- if (uri == node->_parents.end()) {
- // This node has no parents. Stop here.
- result.make_identity();
- return;
- }
- const UpRelationPointers &urp = (*uri).second;
- if (urp.empty()) {
- // Again, this node has no parents.
- result.make_identity();
- return;
- }
- const NodeRelation *parent_arc = (const NodeRelation *)NULL;
- if (urp.size() == 1) {
- // There is only one parent, so there's no doubt as to which arc
- // to choose.
- parent_arc = *(urp.begin());
- } else {
- // The node has multiple parents, and we have a list of arcs in
- // arc_list_begin .. arc_list_end. If any of the parents is
- // mentioned in the list, we must choose that parent.
- for (InputIterator ri = arc_list_begin;
- parent_arc == (NodeRelation *)NULL && ri != arc_list_end;
- ++ri) {
- if ((*ri)->get_child() == node) {
- parent_arc = (*ri);
- }
- }
- if (parent_arc == (NodeRelation *)NULL) {
- // No, it wasn't mentioned. Issue a warning and use the first
- // one.
- graph_cat.warning()
- << *node << " has multiple parents; wrt() ambiguous.\n";
- parent_arc = *(urp.begin());
- }
- }
- get_uncached_net_transition(parent_arc->get_parent(),
- arc_list_begin, arc_list_end,
- result,
- graph_type);
- TransitionWrapper next = TransitionWrapper::init_from(result);
- next.extract_from(parent_arc);
- result.compose_in_place(next);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: cached_wrt_base
- // Description: The implementation of wrt_base, below, but always
- // uses the cached value. This is the normal behavior.
- ////////////////////////////////////////////////////////////////////
- template<class InputIterator1, class InputIterator2, class TransitionWrapper>
- void
- cached_wrt_base(const Node *from,
- InputIterator1 from_arcs_begin, InputIterator1 from_arcs_end,
- const Node *to,
- InputIterator2 to_arcs_begin, InputIterator2 to_arcs_end,
- TransitionWrapper &result,
- TypeHandle graph_type) {
- UpdateSeq now = last_graph_update[graph_type];
- TransitionWrapper net_from_trans = TransitionWrapper::init_from(result);
- get_cached_net_transition(from, from_arcs_begin, from_arcs_end, now,
- net_from_trans, graph_type);
- get_cached_net_transition(to, to_arcs_begin, to_arcs_end, now,
- result, graph_type);
-
- #ifndef NDEBUG
- if (paranoid_wrt) {
- // We don't entirely trust the caching to work flawlessly. Go
- // ahead and compute the uncached transition just to doublecheck.
- TransitionWrapper check_from_trans =
- TransitionWrapper::init_from(result);
- TransitionWrapper check_to_trans =
- TransitionWrapper::init_from(result);
- get_uncached_net_transition(from, from_arcs_begin, from_arcs_end,
- check_from_trans, graph_type);
- if (check_from_trans.compare_to(net_from_trans) != 0) {
- graph_cat.warning()
- << "WRT cache from " << *from << " is invalid!\n"
- << " cached value is " << net_from_trans << "\n"
- << " should be " << check_from_trans << "\n";
- net_from_trans = check_from_trans;
- }
-
- get_uncached_net_transition(to, to_arcs_begin, to_arcs_end,
- check_to_trans, graph_type);
- if (check_to_trans.compare_to(result) != 0) {
- graph_cat.warning()
- << "WRT cache to " << *to << " is invalid!\n"
- << " cached value is " << result << "\n"
- << " should be " << check_to_trans << "\n";
- result = check_to_trans;
- }
- }
- #endif
- result.invert_compose_in_place(net_from_trans);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: uncached_wrt_base
- // Description: The implementation of wrt_base, below, but never
- // cached.
- ////////////////////////////////////////////////////////////////////
- template<class InputIterator1, class InputIterator2, class TransitionWrapper>
- void
- uncached_wrt_base(const Node *from,
- InputIterator1 from_arcs_begin, InputIterator1 from_arcs_end,
- const Node *to,
- InputIterator2 to_arcs_begin, InputIterator2 to_arcs_end,
- TransitionWrapper &result,
- TypeHandle graph_type) {
- // UpdateSeq now = last_graph_update[graph_type];
- TransitionWrapper net_from_trans = TransitionWrapper::init_from(result);
- get_uncached_net_transition(from, from_arcs_begin, from_arcs_end,
- net_from_trans, graph_type);
- get_uncached_net_transition(to, to_arcs_begin, to_arcs_end,
- result, graph_type);
- result.invert_compose_in_place(net_from_trans);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: wrt_base
- // Description: Returns the net transition from the node "to"
- // to the node "from".
- //
- // If [from_arcs_begin..from_arcs_end) is nonempty, it
- // contains a list of NodeRelation pointers to resolve
- // ambiguities when a node with multiple parents is
- // encountered as an ancestor of the from node. If any
- // of the parents is listed, that parent will be chosen.
- //
- // Similarly with [to_arcs_begin..to_arcs_end).
- //
- // wrt_base() is a low-level implementation; use the
- // various wrt() wrappers instead.
- ////////////////////////////////////////////////////////////////////
- template<class InputIterator1, class InputIterator2, class TransitionWrapper>
- INLINE void
- wrt_base(const Node *from,
- InputIterator1 from_arcs_begin, InputIterator1 from_arcs_end,
- const Node *to,
- InputIterator2 to_arcs_begin, InputIterator2 to_arcs_end,
- TransitionWrapper &result,
- TypeHandle graph_type) {
- if (cache_wrt) {
- cached_wrt_base(from, from_arcs_begin, from_arcs_end,
- to, to_arcs_begin, to_arcs_end,
- result, graph_type);
- } else {
- uncached_wrt_base(from, from_arcs_begin, from_arcs_end,
- to, to_arcs_begin, to_arcs_end,
- result, graph_type);
- }
- }
- template<class TransitionWrapper>
- INLINE void
- wrt(const Node *from, const Node *to,
- TransitionWrapper &result, TypeHandle graph_type) {
- // In the normal wrt() interface, we have no from_arcs or to_arcs
- // list. Supply empty lists for both.
- const NodeRelation *arc = NULL;
- wrt_base(from, &arc, &arc, to, &arc, &arc, result, graph_type);
- }
- template<class InputIterator, class TransitionWrapper>
- INLINE void
- wrt(const Node *from,
- InputIterator from_arcs_begin, InputIterator from_arcs_end,
- const Node *to,
- TransitionWrapper &result, TypeHandle graph_type) {
- const NodeRelation *arc = NULL;
- wrt_base(from, from_arcs_begin, from_arcs_end, to, &arc, &arc,
- result, graph_type);
- }
- template<class InputIterator, class TransitionWrapper>
- INLINE void
- wrt(const Node *from,
- const Node *to,
- InputIterator to_arcs_begin, InputIterator to_arcs_end,
- TransitionWrapper &result, TypeHandle graph_type) {
- const NodeRelation *arc = NULL;
- wrt_base(from, &arc, &arc, to, to_arcs_begin, to_arcs_end,
- result, graph_type);
- }
- template<class InputIterator1, class InputIterator2, class TransitionWrapper>
- INLINE void
- wrt(const Node *from,
- InputIterator1 from_arcs_begin, InputIterator1 from_arcs_end,
- const Node *to,
- InputIterator2 to_arcs_begin, InputIterator2 to_arcs_end,
- TransitionWrapper &result, TypeHandle graph_type) {
- wrt_base(from, from_arcs_begin, from_arcs_end,
- to, to_arcs_begin, to_arcs_end,
- result, graph_type);
- }
- template<class TransitionWrapper>
- INLINE void
- uncached_wrt(const Node *from, const Node *to,
- TransitionWrapper &result, TypeHandle graph_type) {
- const NodeRelation *arc = NULL;
- uncached_wrt_base(from, &arc, &arc, to, &arc, &arc, result, graph_type);
- }
- template<class InputIterator, class TransitionWrapper>
- INLINE void
- uncached_wrt(const Node *from,
- InputIterator from_arcs_begin, InputIterator from_arcs_end,
- const Node *to,
- TransitionWrapper &result, TypeHandle graph_type) {
- const NodeRelation *arc = NULL;
- uncached_wrt_base(from, from_arcs_begin, from_arcs_end, to, &arc, &arc,
- result, graph_type);
- }
- template<class InputIterator, class TransitionWrapper>
- INLINE void
- uncached_wrt(const Node *from,
- const Node *to,
- InputIterator to_arcs_begin, InputIterator to_arcs_end,
- TransitionWrapper &result, TypeHandle graph_type) {
- const NodeRelation *arc = NULL;
- uncached_wrt_base(from, &arc, &arc, to, to_arcs_begin, to_arcs_end,
- result, graph_type);
- }
- template<class InputIterator1, class InputIterator2, class TransitionWrapper>
- INLINE void
- uncached_wrt(const Node *from,
- InputIterator1 from_arcs_begin, InputIterator1 from_arcs_end,
- const Node *to,
- InputIterator2 to_arcs_begin, InputIterator2 to_arcs_end,
- TransitionWrapper &result, TypeHandle graph_type) {
- uncached_wrt_base(from, from_arcs_begin, from_arcs_end,
- to, to_arcs_begin, to_arcs_end,
- result, graph_type);
- }
- template<class TransitionWrapper>
- Node *
- wrt_subtree(NodeRelation *arc, Node *to, TransitionWrapper &result,
- TypeHandle graph_type) {
- if (!cache_wrt) {
- // If we aren't caching wrt, do this the hard way.
- uncached_wrt(arc->get_child(), &arc, &arc + 1, to, result, graph_type);
- return to;
- }
- UpdateSeq now = last_graph_update[graph_type];
- // First, determine the net transition up to the top of the current
- // subtree.
- Node *top_subtree;
- get_cached_net_transition(arc, top_subtree, now, result, graph_type);
- if (top_subtree == to || to == (Node *)NULL) {
- // If the top of the subtree is the node we asked to wrt to,
- // excellent! Stop here.
- } else {
- // Otherwise, it must be the case that the node we want to wrt to is
- // some descendent of the top_subtree node. It also therefore
- // follows that this node has exactly one parent.
-
- nassertr(to->get_num_parents(graph_type) == 1, NULL);
- NodeRelation *to_arc = to->get_parent(graph_type, 0);
-
- // Save the result from the first pass.
- TransitionWrapper net_from_trans = result;
-
- // Now determine the net transition to the top of the subtree from
- // this arc. It had better be the same subtree!
- Node *top_subtree_2;
- get_cached_net_transition(to_arc, top_subtree_2, now, result, graph_type);
- nassertr(top_subtree == top_subtree_2, NULL);
-
- // And now compute the actual wrt.
- result.invert_compose_in_place(net_from_trans);
- }
- #ifndef NDEBUG
- if (paranoid_wrt) {
- // Now check the results.
- TransitionWrapper check_trans =
- TransitionWrapper::init_from(result);
- uncached_wrt(arc->get_child(), &arc, &arc + 1, to, check_trans,
- graph_type);
- if (check_trans.compare_to(result) != 0) {
- graph_cat.warning()
- << "WRT subtree cache from " << *arc->get_child() << " to ";
- if (to == (Node *)NULL) {
- graph_cat.warning(false) << "(top)";
- } else {
- graph_cat.warning(false) << *to;
- }
- graph_cat.warning(false)
- << " is invalid!\n"
- << " cached value is " << result << "\n"
- << " should be " << check_trans << "\n";
- result = check_trans;
- }
- }
- #endif
- return top_subtree;
- }
|