mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 19:08:55 -04:00
716 lines
26 KiB
C++
716 lines
26 KiB
C++
// Filename: node.cxx
|
|
// Created by: drose (27Oct98)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
|
//
|
|
// All use of this software is subject to the terms of the Panda 3d
|
|
// Software license. You should have received a copy of this license
|
|
// along with this source code; you will also find a current copy of
|
|
// the license at http://www.panda3d.org/license.txt .
|
|
//
|
|
// To contact the maintainers of this program write to
|
|
// panda3d@yahoogroups.com .
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "node.h"
|
|
#include "nodeRelation.h"
|
|
|
|
#include <bamWriter.h>
|
|
#include <bamReader.h>
|
|
#include <datagramIterator.h>
|
|
#include <datagram.h>
|
|
#include <indent.h>
|
|
|
|
NodeConnection Node::_empty_connection;
|
|
TypeHandle Node::_type_handle;
|
|
Node* const Node::Null = (Node*)0L;
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
Node::
|
|
Node() {
|
|
MemoryUsage::update_type(this, this);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::Copy Constructor
|
|
// Access: Public
|
|
// Description: The Node copy constructor does not copy children.
|
|
// Use copy_subgraph() if you want a deep copy of the
|
|
// node and all of its children. Also, you should use
|
|
// make_copy() if you just want a typed copy of the Node
|
|
// (without children).
|
|
////////////////////////////////////////////////////////////////////
|
|
Node::
|
|
Node(const Node ©) :
|
|
TypedWritable(copy),
|
|
BoundedObject(copy),
|
|
ReferenceCount(copy)
|
|
{
|
|
MemoryUsage::update_type(this, this);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::Copy Assignment Operator
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void Node::
|
|
operator = (const Node ©) {
|
|
TypedWritable::operator = (copy);
|
|
BoundedObject::operator = (copy);
|
|
ReferenceCount::operator = (copy);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::Destructor
|
|
// Access: Public, Virtual
|
|
// Description: When a Node destructs, all of its arcs must be
|
|
// deleted as well.
|
|
////////////////////////////////////////////////////////////////////
|
|
Node::
|
|
~Node() {
|
|
// We'd better not have any arcs pointing into this node, since
|
|
// we're destructing it now. If we do, the destructor was called in
|
|
// error.
|
|
int i;
|
|
for (i = 0; i < max_node_graphs; i++) {
|
|
UpRelationPointers &urp = _connections[i].get_up();
|
|
nassertv(urp.empty());
|
|
}
|
|
|
|
// Now disconnect all the child arcs.
|
|
for (i = 0; i < max_node_graphs; i++) {
|
|
DownRelationPointers &drp = _connections[i].get_down();
|
|
|
|
DownRelationPointers::iterator drpi;
|
|
for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
|
|
NodeRelation *arc = (*drpi);
|
|
nassertv(arc != (NodeRelation *)NULL);
|
|
|
|
// This deletes the arc and anything below it through the magic
|
|
// of reference-counting.
|
|
arc->detach_below();
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::make_copy
|
|
// Access: Public, Virtual
|
|
// Description: Returns a newly-allocated Node that is a shallow copy
|
|
// of this one. It will be a different Node pointer,
|
|
// but its internal data may or may not be shared with
|
|
// that of the original Node. No children will be
|
|
// copied.
|
|
////////////////////////////////////////////////////////////////////
|
|
Node *Node::
|
|
make_copy() const {
|
|
return new Node(*this);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::copy_subgraph
|
|
// Access: Public
|
|
// Description: Allocates and returns a complete copy of this node
|
|
// and the entire scene graph rooted at this node. Some
|
|
// data may still be shared from the original
|
|
// (e.g. vertex index tables), but nothing that will
|
|
// impede normal use of the node.
|
|
////////////////////////////////////////////////////////////////////
|
|
Node *Node::
|
|
copy_subgraph(TypeHandle graph_type) const {
|
|
InstanceMap inst_map;
|
|
return r_copy_subgraph(graph_type, inst_map);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::safe_to_flatten
|
|
// Access: Public, Virtual
|
|
// Description: Returns true if it is generally safe to flatten out
|
|
// this particular kind of Node by duplicating
|
|
// instances, false otherwise (for instance, a Camera
|
|
// cannot be safely flattened, because the Camera
|
|
// pointer itself is meaningful).
|
|
////////////////////////////////////////////////////////////////////
|
|
bool Node::
|
|
safe_to_flatten() const {
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::safe_to_transform
|
|
// Access: Public, Virtual
|
|
// Description: Returns true if it is generally safe to transform
|
|
// this particular kind of Node by calling the xform()
|
|
// method, false otherwise. For instance, it's usually
|
|
// a bad idea to attempt to xform a Character.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool Node::
|
|
safe_to_transform() const {
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::safe_to_combine
|
|
// Access: Public, Virtual
|
|
// Description: Returns true if it is generally safe to combine
|
|
// this particular kind of Node with other kinds of
|
|
// Nodes, adding children or whatever. For instance, an
|
|
// LODNode should not be combined with any other node,
|
|
// because its set of children is meaningful.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool Node::
|
|
safe_to_combine() const {
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::xform
|
|
// Access: Public, Virtual
|
|
// Description: Transforms the contents of this node by the indicated
|
|
// matrix, if it means anything to do so. For most
|
|
// kinds of nodes, this does nothing.
|
|
////////////////////////////////////////////////////////////////////
|
|
void Node::
|
|
xform(const LMatrix4f &) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::combine_with
|
|
// Access: Public, Virtual
|
|
// Description: Collapses this node with the other node, if possible,
|
|
// and returns a pointer to the combined node, or NULL
|
|
// if the two nodes cannot safely be combined.
|
|
//
|
|
// The return value may be this, other, or a new node
|
|
// altogether.
|
|
//
|
|
// This function is called from GraphReducer::flatten(),
|
|
// and need not deal with children; its job is just to
|
|
// decide whether to collapse the two nodes and what the
|
|
// collapsed node should look like.
|
|
////////////////////////////////////////////////////////////////////
|
|
Node *Node::
|
|
combine_with(Node *other) {
|
|
// An unadorned Node always combines with any other Nodes by
|
|
// yielding completely. However, if we are actually some fancy Node
|
|
// type that derives from Node but didn't redefine this function, we
|
|
// should refuse to combine.
|
|
if (is_exact_type(get_class_type())) {
|
|
// No, we're an ordinary Node.
|
|
return other;
|
|
|
|
} else if (other->is_exact_type(get_class_type())) {
|
|
// We're not an ordinary Node, but the other one is.
|
|
return this;
|
|
}
|
|
|
|
// We're something other than an ordinary Node. Don't combine.
|
|
return (Node *)NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::transform_changed
|
|
// Access: Public, Virtual
|
|
// Description: Called whenever the transform matrix on one of the
|
|
// arcs directly above this node has changed. This is
|
|
// simply a hook so the node can do something
|
|
// appropriate. It does not get called when arcs far
|
|
// above the node change.
|
|
////////////////////////////////////////////////////////////////////
|
|
void Node::
|
|
transform_changed(NodeRelation *) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::get_num_parents
|
|
// Access: Public
|
|
// Description: Returns the number of parent arcs of the indicated
|
|
// type (e.g. RenderRelation::get_class_type()) the node
|
|
// has.
|
|
////////////////////////////////////////////////////////////////////
|
|
int Node::
|
|
get_num_parents(TypeHandle type) const {
|
|
const UpRelationPointers &urp = find_connection(type).get_up();
|
|
return urp.size();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::get_parent
|
|
// Access: Public
|
|
// Description: Returns the nth parent arc of the indicated type the
|
|
// node has. The index must be in the range 0 <= index
|
|
// < get_num_parents(type).
|
|
////////////////////////////////////////////////////////////////////
|
|
NodeRelation *Node::
|
|
get_parent(TypeHandle type, int index) const {
|
|
const UpRelationPointers &urp = find_connection(type).get_up();
|
|
nassertr(index >= 0 && index < (int)urp.size(),
|
|
(NodeRelation *)NULL);
|
|
return urp[index];
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::get_num_children
|
|
// Access: Public
|
|
// Description: Returns the number of child arcs of the indicated
|
|
// type (e.g. RenderRelation::get_class_type()) the node
|
|
// has.
|
|
////////////////////////////////////////////////////////////////////
|
|
int Node::
|
|
get_num_children(TypeHandle type) const {
|
|
const DownRelationPointers &drp = find_connection(type).get_down();
|
|
return drp.size();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::get_child
|
|
// Access: Public
|
|
// Description: Returns the nth child arc of the indicated type the
|
|
// node has. The index must be in the range 0 <= index
|
|
// < get_num_children(type).
|
|
////////////////////////////////////////////////////////////////////
|
|
NodeRelation *Node::
|
|
get_child(TypeHandle type, int index) const {
|
|
const DownRelationPointers &drp = find_connection(type).get_down();
|
|
nassertr(index >= 0 && index < (int)drp.size(),
|
|
(NodeRelation *)NULL);
|
|
return drp[index];
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::app_traverse
|
|
// Access: Public, Virtual
|
|
// Description: This hook function is called on each node visited
|
|
// during the App traversal. The ArcChain passed in
|
|
// represents the complete chain from the root of the
|
|
// graph to this node, if it is known.
|
|
////////////////////////////////////////////////////////////////////
|
|
void Node::
|
|
app_traverse(const ArcChain &) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::draw_traverse
|
|
// Access: Public, Virtual
|
|
// Description: This hook function is called on each node visited
|
|
// during the Draw traversal. The ArcChain passed in
|
|
// represents the complete chain from the root of the
|
|
// graph to this node, if it is known.
|
|
////////////////////////////////////////////////////////////////////
|
|
void Node::
|
|
draw_traverse(const ArcChain &) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::dgraph_traverse
|
|
// Access: Public, Virtual
|
|
// Description: This hook function is called on each node visited
|
|
// during the data graph traversal. The ArcChain passed
|
|
// in represents the complete chain from the root of the
|
|
// graph to this node, if it is known.
|
|
////////////////////////////////////////////////////////////////////
|
|
void Node::
|
|
dgraph_traverse(const ArcChain &) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::sub_render
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
bool Node::
|
|
sub_render(const AllAttributesWrapper &, AllTransitionsWrapper &,
|
|
RenderTraverser *) {
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::has_sub_render
|
|
// Access: Public, Virtual
|
|
// Description: Should be redefined to return true if the function
|
|
// sub_render(), above, expects to be called during
|
|
// traversal.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool Node::
|
|
has_sub_render() const {
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::output
|
|
// Access: Public, Virtual
|
|
// Description: Writes a brief description of the node to the
|
|
// indicated output stream. This is invoked by the <<
|
|
// operator. It may be overridden in derived classes to
|
|
// include some information relevant to the class.
|
|
////////////////////////////////////////////////////////////////////
|
|
void Node::
|
|
output(ostream &out) const {
|
|
out << get_type();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::write
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void Node::
|
|
write(ostream &out, int indent_level) const {
|
|
indent(out, indent_level) << *this << "\n";
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::p_find_connection
|
|
// Access: Private
|
|
// Description: The non-inline implementation of find_connection().
|
|
////////////////////////////////////////////////////////////////////
|
|
const NodeConnection &Node::
|
|
p_find_connection(TypeHandle graph_type) const {
|
|
// _connections[0] is already tested by the inline implementation.
|
|
for (int i = 1; i < max_node_graphs; i++) {
|
|
if (_connections[i].get_graph_type() == graph_type) {
|
|
return _connections[i];
|
|
}
|
|
}
|
|
return _empty_connection;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::p_update_connection
|
|
// Access: Private
|
|
// Description: The non-inline implementation of update_connection().
|
|
////////////////////////////////////////////////////////////////////
|
|
NodeConnection *Node::
|
|
p_update_connection(TypeHandle graph_type) {
|
|
// _connections[0] is already tested by the inline implementation.
|
|
int i;
|
|
for (i = 1; i < max_node_graphs; i++) {
|
|
if (_connections[i].get_graph_type() == graph_type) {
|
|
return &_connections[i];
|
|
}
|
|
}
|
|
|
|
// No such connection; can we create a new one?
|
|
for (i = 0; i < max_node_graphs; i++) {
|
|
if (_connections[i].is_empty()) {
|
|
_connections[i].set_graph_type(graph_type);
|
|
return &_connections[i];
|
|
}
|
|
}
|
|
|
|
// Too bad.
|
|
return (NodeConnection *)NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::propagate_stale_bound
|
|
// Access: Protected, Virtual
|
|
// Description: Called by BoundedObject::mark_bound_stale(), this
|
|
// should make sure that all bounding volumes that
|
|
// depend on this one are marked stale also.
|
|
////////////////////////////////////////////////////////////////////
|
|
void Node::
|
|
propagate_stale_bound() {
|
|
// Mark all of our parent arcs, in all graphs, stale as well.
|
|
for (int i = 0; i < max_node_graphs; i++) {
|
|
const UpRelationPointers &urp = _connections[i].get_up();
|
|
UpRelationPointers::const_iterator urpi;
|
|
for (urpi = urp.begin(); urpi != urp.end(); ++urpi) {
|
|
(*urpi)->mark_bound_stale();
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::r_copy_subgraph
|
|
// Access: Protected, Virtual
|
|
// Description: This is the recursive implementation of copy_subgraph().
|
|
// It returns a copy of the entire subgraph rooted at
|
|
// this node.
|
|
//
|
|
// Note that it includes the parameter inst_map, which
|
|
// is a map type, and is not (and cannot be) exported
|
|
// from PANDA.DLL. Thus, any derivative of Node that is
|
|
// not also a member of PANDA.DLL *cannot* access this
|
|
// map.
|
|
////////////////////////////////////////////////////////////////////
|
|
Node *Node::
|
|
r_copy_subgraph(TypeHandle graph_type, Node::InstanceMap &inst_map) const {
|
|
Node *copy = make_copy();
|
|
nassertr(copy != (Node *)NULL, NULL);
|
|
if (copy->get_type() != get_type()) {
|
|
graph_cat.warning()
|
|
<< "Don't know how to copy nodes of type " << get_type() << "\n";
|
|
}
|
|
|
|
copy->r_copy_children(this, graph_type, inst_map);
|
|
return copy;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::r_copy_children
|
|
// Access: Protected, Virtual
|
|
// Description: This is called by r_copy_subgraph(); the copy has
|
|
// already been made of this particular node (and this
|
|
// is the copy); this function's job is to copy all of
|
|
// the children from the original.
|
|
//
|
|
// Note that it includes the parameter inst_map, which
|
|
// is a map type, and is not (and cannot be) exported
|
|
// from PANDA.DLL. Thus, any derivative of Node that is
|
|
// not also a member of PANDA.DLL *cannot* access this
|
|
// map, and probably should not even override this
|
|
// function.
|
|
////////////////////////////////////////////////////////////////////
|
|
void Node::
|
|
r_copy_children(const Node *from, TypeHandle graph_type,
|
|
Node::InstanceMap &inst_map) {
|
|
const DownRelationPointers &drp =
|
|
from->find_connection(graph_type).get_down();
|
|
DownRelationPointers::const_iterator drpi;
|
|
for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
|
|
NodeRelation *source_arc = (*drpi);
|
|
Node *source_child = source_arc->get_child();
|
|
nassertv(source_child != (Node *)NULL);
|
|
|
|
Node *dest_child;
|
|
|
|
// Check to see if we have already copied this child. If we
|
|
// have, use the copy. In this way, a subgraph that contains
|
|
// instances will be correctly duplicated into another subgraph
|
|
// that also contains its own instances.
|
|
InstanceMap::const_iterator ci;
|
|
ci = inst_map.find(source_child);
|
|
if (ci != inst_map.end()) {
|
|
dest_child = (*ci).second;
|
|
} else {
|
|
dest_child = source_child->r_copy_subgraph(graph_type, inst_map);
|
|
inst_map[source_child] = dest_child;
|
|
}
|
|
|
|
NodeRelation *dest_arc =
|
|
NodeRelation::create_typed_arc(graph_type, this, dest_child);
|
|
nassertv(dest_arc != (NodeRelation *)NULL);
|
|
nassertv(dest_arc->is_exact_type(graph_type));
|
|
|
|
dest_arc->copy_transitions_from(source_arc);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::write_datagram
|
|
// Access: Public
|
|
// Description: Function to write the important information in
|
|
// the particular object to a Datagram
|
|
////////////////////////////////////////////////////////////////////
|
|
void Node::
|
|
write_datagram(BamWriter *manager, Datagram &me) {
|
|
// A node should not write out its UpRelations. This is because if
|
|
// a node is written out from the middle of the graph, then most
|
|
// likely we only want to write it and its children. If we did
|
|
// write out all of the UpRelations then writing any node in a graph
|
|
// would cause the entire graph to be written out.
|
|
|
|
// First, count up the number of NodeConnections that are nonempty.
|
|
int num_connections = 0;
|
|
int i;
|
|
for (i = 0; i < max_node_graphs; i++) {
|
|
if (!_connections[i].is_empty()) {
|
|
num_connections++;
|
|
}
|
|
}
|
|
|
|
me.add_uint16(num_connections);
|
|
|
|
// Now write them out.
|
|
for (i = 0; i < max_node_graphs; i++) {
|
|
if (!_connections[i].is_empty()) {
|
|
manager->write_handle(me, _connections[i].get_graph_type());
|
|
|
|
const DownRelationPointers &drp = _connections[i].get_down();
|
|
me.add_uint16(drp.size());
|
|
DownRelationPointers::const_iterator drpi;
|
|
for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
|
|
NodeRelation *relation = (*drpi);
|
|
manager->write_pointer(me, relation);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::complete_pointers
|
|
// Access: Public
|
|
// Description: Takes in a vector of pointers to TypedWritable
|
|
// objects that correspond to all the requests for
|
|
// pointers that this object made to BamReader.
|
|
////////////////////////////////////////////////////////////////////
|
|
int Node::
|
|
complete_pointers(vector_typedWritable &p_list, BamReader *manager) {
|
|
if (manager->get_file_minor_ver() < 3) {
|
|
// In bam versions before 3.3, this function does nothing (since
|
|
// the arcs are completely responsible for adding themselves to
|
|
// our list); we only need to return the number of pointers we
|
|
// expected to receive.
|
|
|
|
// As of 5/7/01, we no longer store this number, as a memory
|
|
// optimization. This means bams before 3.3 cannot be reliably
|
|
// loaded.
|
|
|
|
graph_cat.warning()
|
|
<< "Unable to reliably load bam version "
|
|
<< manager->get_file_major_ver() << "."
|
|
<< manager->get_file_minor_ver() << "\n";
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Beginning at bam version 3.3, we are responsible for adding our
|
|
// child arcs directly.
|
|
|
|
int count = 0;
|
|
|
|
for (int i = 0; i < max_node_graphs; i++) {
|
|
if (!_connections[i].is_empty()) {
|
|
DownRelationPointers &drp = _connections[i].get_down();
|
|
|
|
DownRelationPointers::iterator drpi;
|
|
for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
|
|
(*drpi) = DCAST(NodeRelation, p_list[count]);
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::make_Node
|
|
// Access: Protected
|
|
// Description: Factory method to generate a node object
|
|
////////////////////////////////////////////////////////////////////
|
|
TypedWritable* Node::
|
|
make_Node(const FactoryParams ¶ms) {
|
|
Node *me = new Node;
|
|
DatagramIterator scan;
|
|
BamReader *manager;
|
|
|
|
parse_params(params, scan, manager);
|
|
me->fillin(scan, manager);
|
|
return me;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::fillin
|
|
// Access: Protected
|
|
// Description: Function that reads out of the datagram (or asks
|
|
// manager to read) all of the data that is needed to
|
|
// re-create this object and stores it in the appropiate
|
|
// place
|
|
////////////////////////////////////////////////////////////////////
|
|
void Node::
|
|
fillin(DatagramIterator &scan, BamReader *manager) {
|
|
if (manager->get_file_minor_ver() < 3) {
|
|
// In bam versions before 3.3, we only need to count up the total
|
|
// number of arcs across all types, because we don't add the arc
|
|
// pointers explicitly here.
|
|
int num_types = scan.get_uint16();
|
|
|
|
while (num_types > 0) {
|
|
int num_arcs = scan.get_uint16();
|
|
while (num_arcs > 0) {
|
|
manager->read_pointer(scan, this);
|
|
num_arcs--;
|
|
}
|
|
num_types--;
|
|
}
|
|
|
|
} else {
|
|
// Beginning at bam version 3.3, we do all the reading of our
|
|
// children arcs of all types, which means we need to record the
|
|
// numbers of each type of children. We do this by recording a
|
|
// series of NULL pointers in our NodeConnections.
|
|
|
|
int num_connections = scan.get_uint16();
|
|
if (num_connections > max_node_graphs) {
|
|
// Oops, too many graph types in this bam file. We'll have to
|
|
// discard some.
|
|
graph_cat.error()
|
|
<< "Bam file specifies " << num_connections << " graph types for "
|
|
<< *this << "; this version of Panda can only support "
|
|
<< max_node_graphs << " simultaneous graph types.\n";
|
|
}
|
|
for (int i = 0; i < num_connections; i++) {
|
|
TypeHandle type = manager->read_handle(scan);
|
|
|
|
if (i < max_node_graphs) {
|
|
_connections[i].set_graph_type(type);
|
|
|
|
DownRelationPointers &drp = _connections[i].get_down();
|
|
int num_arcs = scan.get_uint16();
|
|
while (num_arcs > 0) {
|
|
manager->read_pointer(scan, this);
|
|
drp.push_back((NodeRelation *)NULL);
|
|
num_arcs--;
|
|
}
|
|
} else {
|
|
// Read and discard.
|
|
int num_arcs = scan.get_uint16();
|
|
while (num_arcs > 0) {
|
|
manager->skip_pointer(scan);
|
|
num_arcs--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: Node::register_with_factory
|
|
// Access: Public, Static
|
|
// Description: Factory method to generate a node object
|
|
////////////////////////////////////////////////////////////////////
|
|
void Node::
|
|
register_with_read_factory(void) {
|
|
BamReader::get_factory()->register_factory(get_class_type(), make_Node);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: find_arc
|
|
// Description: Searches for the arc of the indicated type that
|
|
// connects the two indicated nodes. Returns the arc if
|
|
// it exists, or NULL if does not.
|
|
////////////////////////////////////////////////////////////////////
|
|
NodeRelation *
|
|
find_arc(Node *parent, Node *child, TypeHandle graph_type) {
|
|
// We must now walk the RelationPointers list, looking for the
|
|
// matching parent-child arc. We'll start in the child looking for
|
|
// the parent arc, on the assumption there are likely to be fewer
|
|
// parents than children.
|
|
|
|
const UpRelationPointers &urp = child->find_connection(graph_type).get_up();
|
|
UpRelationPointers::const_iterator urpi;
|
|
for (urpi = urp.begin(); urpi != urp.end(); ++urpi) {
|
|
NodeRelation *arc = (*urpi);
|
|
if (arc->get_parent() == parent && arc->get_child() == child) {
|
|
return arc;
|
|
}
|
|
}
|
|
|
|
// There is no matching arc.
|
|
return (NodeRelation *)NULL;
|
|
}
|