bamify NodePath's parents etc too, to better support common nodes

This commit is contained in:
David Rose 2010-02-10 23:50:57 +00:00
parent 9e6bab46ab
commit 981890183b
4 changed files with 220 additions and 54 deletions

View File

@ -84,31 +84,6 @@ any_path(PandaNode *node, Thread *current_thread) {
return result;
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::Constructor
// Access: Published
// Description: Constructs a NodePath with the indicated parent
// NodePath and child node; the child node must be a
// stashed or unstashed child of the parent.
////////////////////////////////////////////////////////////////////
INLINE NodePath::
NodePath(const NodePath &parent, PandaNode *child_node,
Thread *current_thread) :
_error_type(ET_fail)
{
nassertv(!parent.is_empty());
nassertv(child_node != (PandaNode *)NULL);
int pipeline_stage = current_thread->get_pipeline_stage();
_head = PandaNode::get_component(parent._head, child_node, pipeline_stage,
current_thread);
nassertv(_head != (NodePathComponent *)NULL);
if (_head != (NodePathComponent *)NULL) {
_error_type = ET_ok;
}
_backup_key = 0;
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::Copy Constructor
// Access: Published
@ -2387,6 +2362,37 @@ get_name() const {
return node()->get_name();
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::encode_full_path_to_bam_stream
// Access: Published
// Description: Converts the NodePath object into a single
// stream of data using a BamWriter, and returns that
// data as a string string. Returns empty string on
// failure.
//
// This is different from NodePath::write_bam_stream()
// and PandaNode::encode_to_bam_stream(), in that it
// encodes the *entire graph* of all nodes connected to
// the NodePath, including all parent nodes and
// siblings. (The other methods only encode this node
// and the nodes below it.) This may be necessary for
// correct streaming of related NodePaths and
// restoration of instances, etc., but it does mean you
// must detach() a node before writing it if you want to
// limit the nodes that get written.
//
// This method is used by __reduce__ to handle streaming
// of NodePaths to a pickle file.
////////////////////////////////////////////////////////////////////
INLINE string NodePath::
encode_full_path_to_bam_stream() const {
string data;
if (!encode_full_path_to_bam_stream(data)) {
return string();
}
return data;
}
INLINE ostream &operator << (ostream &out, const NodePath &node_path) {
node_path.output(out);

View File

@ -67,6 +67,7 @@
#include "pStatTimer.h"
#include "modelNode.h"
#include "py_panda.h"
#include "bam.h"
// stack seems to overflow on Intel C++ at 7000. If we need more than
// 7000, need to increase stack size.
@ -136,6 +137,36 @@ static ConfigVariableEnum<EmptyNodePathType> empty_node_path
// ***End temporary transition code for operator bool
////////////////////////////////////////////////////////////////////
// Function: NodePath::Constructor
// Access: Published
// Description: Constructs a NodePath with the indicated parent
// NodePath and child node; the child node must be a
// stashed or unstashed child of the parent.
////////////////////////////////////////////////////////////////////
NodePath::
NodePath(const NodePath &parent, PandaNode *child_node,
Thread *current_thread) :
_error_type(ET_fail)
{
nassertv(child_node != (PandaNode *)NULL);
int pipeline_stage = current_thread->get_pipeline_stage();
if (parent.is_empty()) {
// Special case: constructing a NodePath at the root.
_head = PandaNode::attach(NULL, child_node, 0, pipeline_stage, current_thread);
} else {
_head = PandaNode::get_component(parent._head, child_node, pipeline_stage,
current_thread);
}
nassertv(_head != (NodePathComponent *)NULL);
if (_head != (NodePathComponent *)NULL) {
_error_type = ET_ok;
}
_backup_key = 0;
}
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: NodePath::__copy__
@ -236,20 +267,6 @@ __reduce_persist__(PyObject *self, PyObject *pickler) const {
// (e.g. this), and the arguments necessary to reconstruct this
// object.
if (is_empty()) {
// Reconstruct an empty NodePath. Not a 100% reconstruction,
// because we lose the specific error status, but I don't think
// that matters much.
PyObject *this_class = PyObject_Type(self);
if (this_class == NULL) {
return NULL;
}
PyObject *result = Py_BuildValue("(O())", this_class);
Py_DECREF(this_class);
return result;
}
BamWriter *writer = NULL;
if (pickler != NULL) {
PyObject *py_writer = PyObject_GetAttrString(pickler, "bamWriter");
@ -262,13 +279,12 @@ __reduce_persist__(PyObject *self, PyObject *pickler) const {
}
}
// We have a non-empty NodePath. We need to streamify the
// underlying node.
// We have a non-empty NodePath.
string bam_stream;
if (!node()->encode_to_bam_stream(bam_stream, writer)) {
if (!encode_full_path_to_bam_stream(bam_stream, writer)) {
ostringstream stream;
stream << "Could not bamify object of type " << node()->get_type() << "\n";
stream << "Could not bamify " << this;
string message = stream.str();
PyErr_SetString(PyExc_TypeError, message.c_str());
return NULL;
@ -6606,6 +6622,153 @@ write_bam_stream(ostream &out) const {
return okflag;
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::encode_full_path_to_bam_stream
// Access: Published
// Description: Converts the NodePath object into a single
// stream of data using a BamWriter, and stores that
// data in the indicated string. Returns true on
// success, false on failure.
//
// This is different from NodePath::write_bam_stream()
// and PandaNode::encode_to_bam_stream(), in that it
// encodes the *entire graph* of all nodes connected to
// the NodePath, including all parent nodes and
// siblings. (The other methods only encode this node
// and the nodes below it.) This may be necessary for
// correct streaming of related NodePaths and
// restoration of instances, etc., but it does mean you
// must detach() a node before writing it if you want to
// limit the nodes that get written.
//
// This method is used by __reduce__ to handle streaming
// of NodePaths to a pickle file.
////////////////////////////////////////////////////////////////////
bool NodePath::
encode_full_path_to_bam_stream(string &data, BamWriter *writer) const {
data.clear();
ostringstream stream;
DatagramOutputFile dout;
if (!dout.open(stream)) {
return false;
}
BamWriter local_writer;
if (writer == NULL) {
// Create our own writer.
if (!dout.write_header(_bam_header)) {
return false;
}
writer = &local_writer;
}
writer->set_target(&dout);
// Write an initial Datagram to represent the error type and
// number of nodes.
int num_nodes = get_num_nodes();
Datagram dg;
dg.add_uint8(_error_type);
dg.add_int32(num_nodes);
if (!dout.put_datagram(dg)) {
writer->set_target(NULL);
return false;
}
// Now write the nodes, one at a time.
for (int i = 0; i < num_nodes; ++i) {
PandaNode *node = get_node(num_nodes - i - 1);
nassertr(node != NULL, false);
if (!writer->write_object(node)) {
writer->set_target(NULL);
return false;
}
}
writer->set_target(NULL);
data = stream.str();
return true;
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::decode_full_path_from_bam_stream
// Access: Published, Static
// Description: Reads the string created by a previous call to
// encode_full_path_to_bam_stream(), and extracts and
// returns the NodePath on that string. Returns NULL on
// error.
////////////////////////////////////////////////////////////////////
NodePath NodePath::
decode_full_path_from_bam_stream(const string &data, BamReader *reader) {
NodePath result;
istringstream stream(data);
DatagramInputFile din;
if (!din.open(stream)) {
return NodePath::fail();
}
BamReader local_reader;
if (reader == NULL) {
// Create a local reader.
string head;
if (!din.read_header(head, _bam_header.size())) {
return NodePath::fail();
}
if (head != _bam_header) {
return NodePath::fail();
}
reader = &local_reader;
}
reader->set_source(&din);
// One initial datagram to encode the error type, and the number of nodes.
Datagram dg;
if (!din.get_datagram(dg)) {
return NodePath::fail();
}
DatagramIterator dgi(dg);
ErrorType error_type = (ErrorType)dgi.get_uint8();
int num_nodes = dgi.get_int32();
if (num_nodes == 0) {
// An empty NodePath.
result._error_type = error_type;
} else {
// A real NodePath. Ignore error_type.
for (int i = 0; i < num_nodes; ++i) {
TypedWritable *object = reader->read_object();
if (object == (TypedWritable *)NULL ||
!object->is_of_type(PandaNode::get_class_type())) {
reader->set_source(NULL);
return NodePath::fail();
}
if (!reader->resolve()) {
reader->set_source(NULL);
return NodePath::fail();
}
PandaNode *node = DCAST(PandaNode, object);
result = NodePath(result, node);
}
}
reader->set_source(NULL);
return result;
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::find_common_ancestor
// Access: Private, Static
@ -7542,7 +7705,6 @@ py_decode_NodePath_from_bam_stream(const string &data) {
////////////////////////////////////////////////////////////////////
NodePath
py_decode_NodePath_from_bam_stream_persist(PyObject *unpickler, const string &data) {
BamReader *reader = NULL;
if (unpickler != NULL) {
PyObject *py_reader = PyObject_GetAttrString(unpickler, "bamReader");
@ -7555,13 +7717,7 @@ py_decode_NodePath_from_bam_stream_persist(PyObject *unpickler, const string &da
}
}
PT(PandaNode) node = PandaNode::decode_from_bam_stream(data, reader);
if (node == (PandaNode *)NULL) {
PyErr_SetString(PyExc_ValueError, "Could not unpack bam stream");
return NodePath();
}
return NodePath(node);
return NodePath::decode_full_path_from_bam_stream(data, reader);
}
#endif // HAVE_PYTHON

View File

@ -162,8 +162,8 @@ PUBLISHED:
INLINE NodePath(const string &top_node_name, Thread *current_thread = Thread::get_current_thread());
INLINE NodePath(PandaNode *node, Thread *current_thread = Thread::get_current_thread());
INLINE static NodePath any_path(PandaNode *node, Thread *current_thread = Thread::get_current_thread());
INLINE NodePath(const NodePath &parent, PandaNode *child_node,
Thread *current_thread = Thread::get_current_thread());
NodePath(const NodePath &parent, PandaNode *child_node,
Thread *current_thread = Thread::get_current_thread());
INLINE NodePath(const NodePath &copy);
INLINE void operator = (const NodePath &copy);
@ -869,6 +869,10 @@ PUBLISHED:
BLOCKING bool write_bam_file(const string &filename) const;
BLOCKING bool write_bam_stream(ostream &out) const;
INLINE string encode_full_path_to_bam_stream() const;
bool encode_full_path_to_bam_stream(string &data, BamWriter *writer = NULL) const;
static NodePath decode_full_path_from_bam_stream(const string &data, BamReader *reader = NULL);
private:
static NodePathComponent *
find_common_ancestor(const NodePath &a, const NodePath &b,

View File

@ -82,7 +82,7 @@ get_bam_modified() const {
// efficient to use the same BamWriter to serialize all
// of them together.
////////////////////////////////////////////////////////////////////
string TypedWritable::
INLINE string TypedWritable::
encode_to_bam_stream() const {
string data;
if (!encode_to_bam_stream(data)) {