panda3d/panda/src/graph/node.cxx
2001-07-30 20:54:55 +00:00

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 &copy) :
TypedWritable(copy),
BoundedObject(copy),
ReferenceCount(copy)
{
MemoryUsage::update_type(this, this);
}
////////////////////////////////////////////////////////////////////
// Function: Node::Copy Assignment Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void Node::
operator = (const Node &copy) {
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 &params) {
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;
}