|
@@ -11,45 +11,50 @@
|
|
|
#include "config_util.h"
|
|
#include "config_util.h"
|
|
|
|
|
|
|
|
WriteableFactory *BamReader::_factory = (WriteableFactory*)0L;
|
|
WriteableFactory *BamReader::_factory = (WriteableFactory*)0L;
|
|
|
-BamReader* const BamReader::Null = (BamReader*)0L;
|
|
|
|
|
-WriteableFactory* const BamReader::NullFactory = (WriteableFactory*)0L;
|
|
|
|
|
|
|
+BamReader *const BamReader::Null = (BamReader*)0L;
|
|
|
|
|
+WriteableFactory *const BamReader::NullFactory = (WriteableFactory*)0L;
|
|
|
|
|
|
|
|
const int BamReader::_cur_major = _bam_major_ver;
|
|
const int BamReader::_cur_major = _bam_major_ver;
|
|
|
const int BamReader::_cur_minor = _bam_minor_ver;
|
|
const int BamReader::_cur_minor = _bam_minor_ver;
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: BamReader::Destructor
|
|
|
|
|
|
|
+// Function: BamReader::Constructor
|
|
|
// Access: Public
|
|
// Access: Public
|
|
|
// Description:
|
|
// Description:
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
BamReader::
|
|
BamReader::
|
|
|
-~BamReader(void)
|
|
|
|
|
|
|
+BamReader(DatagramGenerator *generator)
|
|
|
|
|
+ : _source(generator)
|
|
|
{
|
|
{
|
|
|
|
|
+ _num_extra_objects = 0;
|
|
|
|
|
+ _pta_id = -1;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: BamReader::Destructor
|
|
|
|
|
+// Access: Public
|
|
|
|
|
+// Description:
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+BamReader::
|
|
|
|
|
+~BamReader() {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
// Function: BamReader::init
|
|
// Function: BamReader::init
|
|
|
// Access: Public
|
|
// Access: Public
|
|
|
-// Description: Does all initialization necessary for BamReader to work
|
|
|
|
|
-// Current this means reading in the Type Map stored as
|
|
|
|
|
-// the header of the file. This TypeMap contains the
|
|
|
|
|
-// name of all types written out and their type indeces
|
|
|
|
|
-// as set when the file was created. This map is used
|
|
|
|
|
-// for later determing the current TypeHandle for each
|
|
|
|
|
-// object written. Each Object is identified in the file
|
|
|
|
|
-// with the old index for space reason.
|
|
|
|
|
|
|
+// Description: Initializes the BamReader prior to reading any
|
|
|
|
|
+// objects from its source.
|
|
|
//
|
|
//
|
|
|
// This returns true if the BamReader successfully
|
|
// This returns true if the BamReader successfully
|
|
|
// initialized, false otherwise.
|
|
// initialized, false otherwise.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
bool BamReader::
|
|
bool BamReader::
|
|
|
-init(void)
|
|
|
|
|
-{
|
|
|
|
|
|
|
+init() {
|
|
|
Datagram header;
|
|
Datagram header;
|
|
|
|
|
|
|
|
- if (_source->is_error())
|
|
|
|
|
- {
|
|
|
|
|
|
|
+ if (_source->is_error()) {
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -66,8 +71,7 @@ init(void)
|
|
|
|
|
|
|
|
// If the major version is different, or the minor version is
|
|
// If the major version is different, or the minor version is
|
|
|
// *newer*, we can't safely load the file.
|
|
// *newer*, we can't safely load the file.
|
|
|
- if (_file_major != _bam_major_ver || _file_minor > _bam_minor_ver)
|
|
|
|
|
- {
|
|
|
|
|
|
|
+ if (_file_major != _bam_major_ver || _file_minor > _bam_minor_ver) {
|
|
|
bam_cat.error()
|
|
bam_cat.error()
|
|
|
<< "Bam file is version " << _file_major << "." << _file_minor
|
|
<< "Bam file is version " << _file_major << "." << _file_minor
|
|
|
<< ".\n";
|
|
<< ".\n";
|
|
@@ -103,189 +107,264 @@ init(void)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: BamReader::read_handle
|
|
|
|
|
|
|
+// Function: BamReader::read_object
|
|
|
// Access: Public
|
|
// Access: Public
|
|
|
-// Description: Reads a TypeHandle out of the Datagram. If the Type
|
|
|
|
|
-// has not been registered yet, BamReader will register
|
|
|
|
|
-// the Type with TypeRegistry
|
|
|
|
|
|
|
+// Description: Reads a single object from the Bam file. If the
|
|
|
|
|
+// object type is known, a new object of the appropriate
|
|
|
|
|
+// type is created and returned; otherwise, NULL is
|
|
|
|
|
+// returned. NULL is also returned when the end of the
|
|
|
|
|
+// file is reached. is_eof() may be called to
|
|
|
|
|
+// differentiate between these two cases.
|
|
|
|
|
+//
|
|
|
|
|
+// This may be called repeatedly to extract out all the
|
|
|
|
|
+// objects in the Bam file, but typically (especially
|
|
|
|
|
+// for scene graph files, indicated with the .bam
|
|
|
|
|
+// extension), only one object is retrieved directly
|
|
|
|
|
+// from the Bam file: the root of the scene graph. The
|
|
|
|
|
+// remaining objects will all be retrieved recursively
|
|
|
|
|
+// by the first object.
|
|
|
|
|
+//
|
|
|
|
|
+// Note that the object returned may not yet be
|
|
|
|
|
+// complete. In particular, some of its pointers may
|
|
|
|
|
+// not be filled in; you must call resolve() to fill in
|
|
|
|
|
+// all the available pointers before you can safely use
|
|
|
|
|
+// any objects returned by read_object().
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-TypeHandle BamReader::
|
|
|
|
|
-read_handle(DatagramIterator& scan)
|
|
|
|
|
-{
|
|
|
|
|
- int id = scan.get_uint16();
|
|
|
|
|
-
|
|
|
|
|
- if (id == 0)
|
|
|
|
|
- {
|
|
|
|
|
- //This indicates an object that should have already been read in,
|
|
|
|
|
- //so return TypeHandle::none() to indicate this.
|
|
|
|
|
|
|
+TypedWriteable *BamReader::
|
|
|
|
|
+read_object() {
|
|
|
|
|
+ nassertr(_num_extra_objects == 0, (TypedWriteable *)NULL);
|
|
|
|
|
+
|
|
|
|
|
+ // First, read the base object.
|
|
|
|
|
+ int object_id = p_read_object();
|
|
|
|
|
+
|
|
|
|
|
+ // Now that object might have included some pointers to other
|
|
|
|
|
+ // objects, which may still need to be read. And those objects
|
|
|
|
|
+ // might in turn require reading additional objects. Read all the
|
|
|
|
|
+ // remaining objects.
|
|
|
|
|
+ while (_num_extra_objects > 0) {
|
|
|
|
|
+ p_read_object();
|
|
|
|
|
+ _num_extra_objects--;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Now look up the pointer of the object we read first. It should
|
|
|
|
|
+ // be available now.
|
|
|
|
|
+ if (object_id == 0) {
|
|
|
#ifndef NDEBUG
|
|
#ifndef NDEBUG
|
|
|
if (bam_cat.is_spam()) {
|
|
if (bam_cat.is_spam()) {
|
|
|
bam_cat.spam()
|
|
bam_cat.spam()
|
|
|
- << "Reading previously read TypeHandle.\n";
|
|
|
|
|
|
|
+ << "Returning NULL\n";
|
|
|
}
|
|
}
|
|
|
#endif
|
|
#endif
|
|
|
- return TypeHandle::none();
|
|
|
|
|
|
|
+ return (TypedWriteable *)NULL;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (_index_map.find(id) == _index_map.end())
|
|
|
|
|
- {
|
|
|
|
|
- //Have not loaded this type before
|
|
|
|
|
- string name = scan.get_string();
|
|
|
|
|
- TypeHandle type = TypeRegistry::ptr()->find_type(name);
|
|
|
|
|
- bool new_type = false;
|
|
|
|
|
-
|
|
|
|
|
- if (type == TypeHandle::none())
|
|
|
|
|
- {
|
|
|
|
|
- //This is a new type we've never heard of before so register it
|
|
|
|
|
- //with the type registry
|
|
|
|
|
- type = TypeRegistry::ptr()->register_dynamic_type(name);
|
|
|
|
|
- bam_cat.warning()
|
|
|
|
|
- << "Bam file contains objects of unknown type: " << type << "\n";
|
|
|
|
|
- new_type = true;
|
|
|
|
|
|
|
+ CreatedObjs::iterator oi = _created_objs.find(object_id);
|
|
|
|
|
+
|
|
|
|
|
+ if (oi == _created_objs.end()) {
|
|
|
|
|
+ bam_cat.error()
|
|
|
|
|
+ << "Undefined object encountered!\n";
|
|
|
|
|
+ return (TypedWriteable *)NULL;
|
|
|
|
|
+
|
|
|
|
|
+ } else {
|
|
|
|
|
+ TypedWriteable *object = (*oi).second;
|
|
|
|
|
+
|
|
|
|
|
+#ifndef NDEBUG
|
|
|
|
|
+ if (bam_cat.is_spam()) {
|
|
|
|
|
+ if (object != (TypedWriteable *)NULL) {
|
|
|
|
|
+ bam_cat.spam()
|
|
|
|
|
+ << "Returning object of type " << object->get_type() << "\n";
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- _index_map[id] = type;
|
|
|
|
|
-
|
|
|
|
|
- // Now pick up the derivation information.
|
|
|
|
|
- int num_parent_classes = scan.get_uint8();
|
|
|
|
|
- for (int i = 0; i < num_parent_classes; i++) {
|
|
|
|
|
- TypeHandle parent_type = read_handle(scan);
|
|
|
|
|
- if (new_type) {
|
|
|
|
|
- TypeRegistry::ptr()->record_derivation(type, parent_type);
|
|
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+ return object;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: BamReader::resolve
|
|
|
|
|
+// Access: Public
|
|
|
|
|
+// Description: This may be called at any time during processing of
|
|
|
|
|
+// the Bam file to resolve all the known pointers so
|
|
|
|
|
+// far. It is usually called at the end of the
|
|
|
|
|
+// processing, after all objects have been read, which
|
|
|
|
|
+// is generally the best time to call it.
|
|
|
|
|
+//
|
|
|
|
|
+// This must be called at least once after reading a
|
|
|
|
|
+// particular object via get_object() in order to
|
|
|
|
|
+// validate that object.
|
|
|
|
|
+//
|
|
|
|
|
+// The return value is true if all objects have been
|
|
|
|
|
+// resolved, or false if some objects are still
|
|
|
|
|
+// outstanding (in which case you will need to call
|
|
|
|
|
+// resolve() again later).
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+bool BamReader::
|
|
|
|
|
+resolve() {
|
|
|
|
|
+ bool all_completed = true;
|
|
|
|
|
+
|
|
|
|
|
+ // Walk through all the objects that still have outstanding pointers.
|
|
|
|
|
+ Requests::iterator ri;
|
|
|
|
|
+ ri = _deferred_pointers.begin();
|
|
|
|
|
+ while (ri != _deferred_pointers.end()) {
|
|
|
|
|
+ TypedWriteable *whom = (*ri).first;
|
|
|
|
|
+ const vector_ushort &pointers = (*ri).second;
|
|
|
|
|
+
|
|
|
|
|
+ // Now make sure we have all of the pointers this object is
|
|
|
|
|
+ // waiting for. If any of the pointers has not yet been read in,
|
|
|
|
|
+ // we can't resolve this object--we can't do anything for a given
|
|
|
|
|
+ // object until we have *all* outstanding pointers for that
|
|
|
|
|
+ // object.
|
|
|
|
|
+
|
|
|
|
|
+ bool is_complete = true;
|
|
|
|
|
+ vector_typedWriteable references;
|
|
|
|
|
+
|
|
|
|
|
+ vector_ushort::const_iterator pi;
|
|
|
|
|
+ for (pi = pointers.begin(); pi != pointers.end() && is_complete; ++pi) {
|
|
|
|
|
+ int object_id = (*pi);
|
|
|
|
|
+
|
|
|
|
|
+ if (object_id == 0) {
|
|
|
|
|
+ // A NULL pointer is a NULL pointer.
|
|
|
|
|
+ references.push_back((TypedWriteable *)NULL);
|
|
|
|
|
+
|
|
|
} else {
|
|
} else {
|
|
|
- if (type.get_parent_towards(parent_type) != parent_type) {
|
|
|
|
|
- bam_cat.warning()
|
|
|
|
|
- << "Bam file indicates a derivation of " << type
|
|
|
|
|
- << " from " << parent_type << " which is no longer true.\n";
|
|
|
|
|
|
|
+ // See if we have the pointer available now.
|
|
|
|
|
+ CreatedObjs::const_iterator oi = _created_objs.find(object_id);
|
|
|
|
|
+ if (oi == _created_objs.end()) {
|
|
|
|
|
+ // No, too bad.
|
|
|
|
|
+ is_complete = false;
|
|
|
|
|
+
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Yes, it's ready.
|
|
|
|
|
+ references.push_back((*oi).second);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if (is_complete) {
|
|
|
|
|
+ // Okay, here's the complete list of pointers for you!
|
|
|
|
|
+ whom->complete_pointers(references, this);
|
|
|
|
|
+
|
|
|
|
|
+ // Now remove this object from the list of things that need
|
|
|
|
|
+ // completion. We have to be a bit careful when deleting things
|
|
|
|
|
+ // from the STL container while we are traversing it.
|
|
|
|
|
+ Requests::iterator old = ri;
|
|
|
|
|
+ ++ri;
|
|
|
|
|
+ _deferred_pointers.erase(old);
|
|
|
|
|
+
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Couldn't complete this object yet; it'll wait for next time.
|
|
|
|
|
+ bam_cat.warning()
|
|
|
|
|
+ << "Unable to complete " << whom->get_type() << "\n";
|
|
|
|
|
+ ++ri;
|
|
|
|
|
+ all_completed = false;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-#ifndef NDEBUG
|
|
|
|
|
- if (bam_cat.is_spam()) {
|
|
|
|
|
- bam_cat.spam()
|
|
|
|
|
- << "Reading TypeHandle for " << _index_map[id] << ".\n";
|
|
|
|
|
|
|
+ if (all_completed) {
|
|
|
|
|
+ finalize();
|
|
|
}
|
|
}
|
|
|
-#endif
|
|
|
|
|
|
|
|
|
|
- return _index_map[id];
|
|
|
|
|
|
|
+ return all_completed;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: BamReader::read_object
|
|
|
|
|
|
|
+// Function: BamReader::read_handle
|
|
|
// Access: Public
|
|
// Access: Public
|
|
|
-// Description: Reads an object definition from the DatagramGenerator
|
|
|
|
|
-// and generates an object of the correct type, and returns
|
|
|
|
|
-// a pointer to that object.
|
|
|
|
|
|
|
+// Description: Reads a TypeHandle out of the Datagram.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-TypedWriteable* BamReader::
|
|
|
|
|
-read_object(void)
|
|
|
|
|
-{
|
|
|
|
|
- Datagram packet, body;
|
|
|
|
|
-
|
|
|
|
|
- //if (_source->empty()) //If the source is empty, then we merely have
|
|
|
|
|
- //{ //back reference read's queue, so clear the queue
|
|
|
|
|
- // clear_queue();
|
|
|
|
|
- // return TypedWriteable::Null;
|
|
|
|
|
- //}
|
|
|
|
|
|
|
+TypeHandle BamReader::
|
|
|
|
|
+read_handle(DatagramIterator &scan) {
|
|
|
|
|
+ // We encode TypeHandles within the Bam file by writing a unique
|
|
|
|
|
+ // index number for each one to the file. When we write a
|
|
|
|
|
+ // particular TypeHandle for the first type, we assign it a new
|
|
|
|
|
+ // index number and then immediately follow it by its definition;
|
|
|
|
|
+ // when we write the same TypeHandle on subsequent times we only
|
|
|
|
|
+ // write the index number.
|
|
|
|
|
+
|
|
|
|
|
+ // Thus, to read a TypeHandle, we first read the index number. If
|
|
|
|
|
+ // it is a number we have not yet encountered, we must then read the
|
|
|
|
|
+ // definition.
|
|
|
|
|
+
|
|
|
|
|
+ // Here's the index number.
|
|
|
|
|
+ int id = scan.get_uint16();
|
|
|
|
|
+
|
|
|
|
|
+ if (id == 0) {
|
|
|
|
|
+ // Index number 0 is always, by convention, TypeHandle::none().
|
|
|
|
|
|
|
|
- if (_source->is_error())
|
|
|
|
|
- {
|
|
|
|
|
- return TypedWriteable::Null;
|
|
|
|
|
|
|
+ // This indicates an object that should have already been read in,
|
|
|
|
|
+ // so return TypeHandle::none() to indicate this.
|
|
|
|
|
+#ifndef NDEBUG
|
|
|
|
|
+ if (bam_cat.is_spam()) {
|
|
|
|
|
+ bam_cat.spam()
|
|
|
|
|
+ << "Read TypeHandle::none().\n";
|
|
|
|
|
+ }
|
|
|
|
|
+#endif
|
|
|
|
|
+ return TypeHandle::none();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (!_source->get_datagram(packet)) {
|
|
|
|
|
- // The datagram source is empty.
|
|
|
|
|
|
|
+ IndexMap::const_iterator mi = _index_map.find(id);
|
|
|
|
|
+ if (mi != _index_map.end()) {
|
|
|
|
|
+ // We've encountered this index number before, so there should be
|
|
|
|
|
+ // no type definition following the id. Simply return the
|
|
|
|
|
+ // TypeHandle we previously associated with the id.
|
|
|
|
|
+ TypeHandle type = (*mi).second;
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
#ifndef NDEBUG
|
|
|
- if (bam_cat.is_debug()) {
|
|
|
|
|
- bam_cat.debug()
|
|
|
|
|
- << "Reached end of bam source.\n";
|
|
|
|
|
|
|
+ if (bam_cat.is_spam()) {
|
|
|
|
|
+ bam_cat.spam()
|
|
|
|
|
+ << "Read TypeHandle for " << type << ".\n";
|
|
|
}
|
|
}
|
|
|
#endif
|
|
#endif
|
|
|
- return TypedWriteable::Null;
|
|
|
|
|
|
|
+ return type;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- //Now pull out the type ID and Object ID from the
|
|
|
|
|
- //datagram and pass the remaining data in that
|
|
|
|
|
- //datagram, the body to the WriteableParam for
|
|
|
|
|
- //creation of the object
|
|
|
|
|
- DatagramIterator scan(packet);
|
|
|
|
|
- TypeHandle type = read_handle(scan);
|
|
|
|
|
- PN_uint16 objId = scan.get_uint16();
|
|
|
|
|
-
|
|
|
|
|
- //Before anything else, check to see if type is none
|
|
|
|
|
- //If that is the case, then we SHOULD have already read
|
|
|
|
|
- //in and created the object (although pointers in that object
|
|
|
|
|
- //may not be fully instanciated yet), so just return a pointer
|
|
|
|
|
- //to that already created obj and don't try to re-create it
|
|
|
|
|
- if (type != TypeHandle::none())
|
|
|
|
|
- {
|
|
|
|
|
- string message = scan.get_remaining_bytes();
|
|
|
|
|
- body.append_data(message.data(), message.size());
|
|
|
|
|
-
|
|
|
|
|
- //Generate FactoryParams object to pass to the factory for
|
|
|
|
|
- //creating the object
|
|
|
|
|
- FactoryParams list;
|
|
|
|
|
- list.add_param(new WriteableParam(body));
|
|
|
|
|
- list.add_param(new BamReaderParam(this));
|
|
|
|
|
-
|
|
|
|
|
- //Due to the recursive nature of reading in objects (and their pointers)
|
|
|
|
|
- //this line is to ensure that objId gets into the map _created_objs
|
|
|
|
|
- //before we call make_instance. It works due to the nature of map.
|
|
|
|
|
- //What happens is that a pair consistenting of objId and some random
|
|
|
|
|
- //pointer is put into the map. But this is okay, since in the
|
|
|
|
|
- //recursion we only refer to this objId for purposes of whether
|
|
|
|
|
- //it is there or not and we immediately override it with a good
|
|
|
|
|
- //value otherwise
|
|
|
|
|
- _created_objs[objId];
|
|
|
|
|
- _created_objs[objId] = _factory->make_instance_more_general(type, list);
|
|
|
|
|
|
|
+ // We haven't encountered this index number before. This means it
|
|
|
|
|
+ // will be immediately followed by the type definition. This
|
|
|
|
|
+ // consists of the string name, followed by the list of parent
|
|
|
|
|
+ // TypeHandles for this type.
|
|
|
|
|
|
|
|
- //Just some sanity checks
|
|
|
|
|
- if (_created_objs[objId] == (TypedWriteable *)NULL) {
|
|
|
|
|
- bam_cat.error()
|
|
|
|
|
- << "Unable to create an object of type " << type << endl;
|
|
|
|
|
|
|
+ string name = scan.get_string();
|
|
|
|
|
+ bool new_type = false;
|
|
|
|
|
|
|
|
- } else if (_created_objs[objId]->get_type() != type) {
|
|
|
|
|
- bam_cat.warning()
|
|
|
|
|
- << "Attempted to create a " << type.get_name() \
|
|
|
|
|
- << " but a " << _created_objs[objId]->get_type() \
|
|
|
|
|
- << " was created instead." << endl;
|
|
|
|
|
|
|
+ TypeHandle type = TypeRegistry::ptr()->find_type(name);
|
|
|
|
|
+ if (type == TypeHandle::none()) {
|
|
|
|
|
+ // We've never heard of this type before! This is really an error
|
|
|
|
|
+ // condition, but we'll do the best we can and declare it
|
|
|
|
|
+ // on-the-fly.
|
|
|
|
|
|
|
|
|
|
+ type = TypeRegistry::ptr()->register_dynamic_type(name);
|
|
|
|
|
+ bam_cat.warning()
|
|
|
|
|
+ << "Bam file contains objects of unknown type: " << type << "\n";
|
|
|
|
|
+ new_type = true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Now pick up the derivation information.
|
|
|
|
|
+ int num_parent_classes = scan.get_uint8();
|
|
|
|
|
+ for (int i = 0; i < num_parent_classes; i++) {
|
|
|
|
|
+ TypeHandle parent_type = read_handle(scan);
|
|
|
|
|
+ if (new_type) {
|
|
|
|
|
+ TypeRegistry::ptr()->record_derivation(type, parent_type);
|
|
|
} else {
|
|
} else {
|
|
|
-#ifndef NDEBUG
|
|
|
|
|
- if (bam_cat.is_spam()) {
|
|
|
|
|
- bam_cat.spam()
|
|
|
|
|
- << "Read a " << _created_objs[objId]->get_type() << "\n";
|
|
|
|
|
|
|
+ if (type.get_parent_towards(parent_type) != parent_type) {
|
|
|
|
|
+ bam_cat.warning()
|
|
|
|
|
+ << "Bam file indicates a derivation of " << type
|
|
|
|
|
+ << " from " << parent_type << " which is no longer true.\n";
|
|
|
}
|
|
}
|
|
|
-#endif
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ bool inserted = _index_map.insert(IndexMap::value_type(id, type)).second;
|
|
|
|
|
+ nassertr(inserted, type);
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
#ifndef NDEBUG
|
|
|
if (bam_cat.is_spam()) {
|
|
if (bam_cat.is_spam()) {
|
|
|
bam_cat.spam()
|
|
bam_cat.spam()
|
|
|
- << "Emptying queue.\n";
|
|
|
|
|
|
|
+ << "Read TypeHandle for " << type << ".\n";
|
|
|
}
|
|
}
|
|
|
#endif
|
|
#endif
|
|
|
- empty_queue();
|
|
|
|
|
|
|
|
|
|
- TypedWriteable *object = _created_objs[objId];
|
|
|
|
|
-
|
|
|
|
|
-#ifndef NDEBUG
|
|
|
|
|
- if (bam_cat.is_spam()) {
|
|
|
|
|
- if (object == (TypedWriteable *)NULL) {
|
|
|
|
|
- bam_cat.spam()
|
|
|
|
|
- << "Returning NULL\n";
|
|
|
|
|
- } else {
|
|
|
|
|
- bam_cat.spam()
|
|
|
|
|
- << "Returning object of type " << object->get_type() << "\n";
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-#endif
|
|
|
|
|
-
|
|
|
|
|
- return object;
|
|
|
|
|
|
|
+ return type;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
@@ -310,22 +389,21 @@ read_object(void)
|
|
|
// object properly.
|
|
// object properly.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void BamReader::
|
|
void BamReader::
|
|
|
-read_pointer(DatagramIterator& scan, TypedWriteable* forWhom)
|
|
|
|
|
-{
|
|
|
|
|
- PN_uint16 objId = scan.get_uint16();
|
|
|
|
|
- _deferred_pointers[forWhom].push_back(objId);
|
|
|
|
|
- // This is safe since we have already read the full datagram for the
|
|
|
|
|
- // object requesting this object. So there can be no collision on
|
|
|
|
|
- // that front.
|
|
|
|
|
-
|
|
|
|
|
- // IMPORTANT NOTE: This does make the assumption that objects are
|
|
|
|
|
- // requested by other objects in the same order that they wrote them
|
|
|
|
|
- // originally.
|
|
|
|
|
-
|
|
|
|
|
- // Don't queue a read of a null pointer or if the object has already
|
|
|
|
|
- // been read
|
|
|
|
|
- if ((objId != 0) && (_created_objs.find(objId) == _created_objs.end()))
|
|
|
|
|
- queue(objId);
|
|
|
|
|
|
|
+read_pointer(DatagramIterator &scan, TypedWriteable *for_whom) {
|
|
|
|
|
+ // Read the object ID, and associate it with the requesting object.
|
|
|
|
|
+ int object_id = scan.get_uint16();
|
|
|
|
|
+ _deferred_pointers[for_whom].push_back(object_id);
|
|
|
|
|
+
|
|
|
|
|
+ // If the object ID is zero (which indicates a NULL pointer), we
|
|
|
|
|
+ // don't have to do anything else.
|
|
|
|
|
+ if (object_id != 0) {
|
|
|
|
|
+ if (_created_objs.count(object_id) == 0) {
|
|
|
|
|
+ // If we don't already have an entry in the map for this object
|
|
|
|
|
+ // ID (that is, we haven't encountered this object before), we
|
|
|
|
|
+ // must remember to read the object definition later.
|
|
|
|
|
+ _num_extra_objects++;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
@@ -336,9 +414,9 @@ read_pointer(DatagramIterator& scan, TypedWriteable* forWhom)
|
|
|
// read_pointer() count times.
|
|
// read_pointer() count times.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void BamReader::
|
|
void BamReader::
|
|
|
-read_pointers(DatagramIterator &scan, TypedWriteable *forWhom, int count) {
|
|
|
|
|
|
|
+read_pointers(DatagramIterator &scan, TypedWriteable *for_whom, int count) {
|
|
|
for (int i = 0; i < count; i++) {
|
|
for (int i = 0; i < count; i++) {
|
|
|
- read_pointer(scan, forWhom);
|
|
|
|
|
|
|
+ read_pointer(scan, for_whom);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -358,13 +436,20 @@ skip_pointer(DatagramIterator &scan) {
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
// Function: BamReader::register_finalize
|
|
// Function: BamReader::register_finalize
|
|
|
// Access: Public
|
|
// Access: Public
|
|
|
-// Description: Register for later finalization
|
|
|
|
|
|
|
+// Description: Should be called by an object reading itself from the
|
|
|
|
|
+// Bam file to indicate that this particular object
|
|
|
|
|
+// would like to receive the finalize() callback when
|
|
|
|
|
+// all the objects and pointers in the Bam file are
|
|
|
|
|
+// completely read.
|
|
|
|
|
+//
|
|
|
|
|
+// This provides a hook for objects (like Characters)
|
|
|
|
|
+// that need to do any additional finalization work
|
|
|
|
|
+// after all of their related pointers are guaranteed to
|
|
|
|
|
+// be filled in.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void BamReader::
|
|
void BamReader::
|
|
|
-register_finalize(TypedWriteable *whom)
|
|
|
|
|
-{
|
|
|
|
|
- if (whom == TypedWriteable::Null)
|
|
|
|
|
- {
|
|
|
|
|
|
|
+register_finalize(TypedWriteable *whom) {
|
|
|
|
|
+ if (whom == TypedWriteable::Null) {
|
|
|
bam_cat.error() << "Can't register a null pointer to finalize!" << endl;
|
|
bam_cat.error() << "Can't register a null pointer to finalize!" << endl;
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
@@ -374,211 +459,220 @@ register_finalize(TypedWriteable *whom)
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
// Function: BamReader::finalize_now
|
|
// Function: BamReader::finalize_now
|
|
|
// Access: Public
|
|
// Access: Public
|
|
|
-// Description: Force finalization of a particular object
|
|
|
|
|
|
|
+// Description: Forces the finalization of a particular object. This
|
|
|
|
|
+// may be called by any of the objects during
|
|
|
|
|
+// finalization, to guarantee finalization ordering
|
|
|
|
|
+// where it is important.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void BamReader::
|
|
void BamReader::
|
|
|
-finalize_now(TypedWriteable *whom)
|
|
|
|
|
-{
|
|
|
|
|
- if (whom == TypedWriteable::Null)
|
|
|
|
|
- {
|
|
|
|
|
- bam_cat.error() << "Can't finalize null pointer!" << endl;
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- if (_finalize_list.find(whom) != _finalize_list.end())
|
|
|
|
|
- {
|
|
|
|
|
|
|
+finalize_now(TypedWriteable *whom) {
|
|
|
|
|
+ nassertv(whom != (TypedWriteable *)NULL);
|
|
|
|
|
+
|
|
|
|
|
+ Finalize::iterator fi = _finalize_list.find(whom);
|
|
|
|
|
+ if (fi != _finalize_list.end()) {
|
|
|
|
|
+ _finalize_list.erase(fi);
|
|
|
whom->finalize();
|
|
whom->finalize();
|
|
|
- _finalize_list.erase(whom);
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- bam_cat.warning() << "Request to finalize object of type "
|
|
|
|
|
- << whom->get_type().get_name() << " failed"
|
|
|
|
|
- << endl;
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: BamReader::empty_queue
|
|
|
|
|
-// Access: Private
|
|
|
|
|
-// Description: For every objId in the queue, reads an object
|
|
|
|
|
-// from the datagram source
|
|
|
|
|
|
|
+// Function: BamReader::get_pta
|
|
|
|
|
+// Access: Public
|
|
|
|
|
+// Description: This function works in conjection with
|
|
|
|
|
+// register_pta(), below, to read a PointerToArray (PTA)
|
|
|
|
|
+// from the Bam file, and unify references to the same
|
|
|
|
|
+// PTA.
|
|
|
|
|
+//
|
|
|
|
|
+// The first time get_pta() encounters a particular PTA,
|
|
|
|
|
+// it will return NULL. This is the indication that the
|
|
|
|
|
+// caller should then read in the data associated with
|
|
|
|
|
+// the PTA, and subsequently call register_pta() with
|
|
|
|
|
+// the address of the filled-in array.
|
|
|
|
|
+//
|
|
|
|
|
+// The next time (and all subsequent times) that
|
|
|
|
|
+// get_pta() encounters this same PTA, it will return
|
|
|
|
|
+// the pointer that was passed with register_pta().
|
|
|
|
|
+//
|
|
|
|
|
+// Also see the READ_PTA() macro, which consolidates all
|
|
|
|
|
+// the work that must be done to read a PTA.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-void BamReader::
|
|
|
|
|
-empty_queue(void) {
|
|
|
|
|
- size_t num_reads = _deferred_reads.size();
|
|
|
|
|
- _deferred_reads.clear();
|
|
|
|
|
|
|
+void *BamReader::
|
|
|
|
|
+get_pta(DatagramIterator &scan) {
|
|
|
|
|
+ nassertr(_pta_id == -1, (void *)NULL);
|
|
|
|
|
+ int id = scan.get_uint16();
|
|
|
|
|
+
|
|
|
|
|
+ if (id == 0) {
|
|
|
|
|
+ // As always, a 0 ID indicates a NULL pointer. The caller will
|
|
|
|
|
+ // not be able to differentiate this case from that of a
|
|
|
|
|
+ // previously-read pointer, but that's OK because the next data in
|
|
|
|
|
+ // the Bam file is the length of the array, which will be
|
|
|
|
|
+ // zero--indicating an empty or NULL array.
|
|
|
|
|
+ return (void *)NULL;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- while (num_reads > 0) {
|
|
|
|
|
- read_object();
|
|
|
|
|
- num_reads--;
|
|
|
|
|
|
|
+ PTAMap::iterator pi = _ptamap.find(id);
|
|
|
|
|
+ if (pi == _ptamap.end()) {
|
|
|
|
|
+ // This is the first time we've encountered this particular ID,
|
|
|
|
|
+ // meaning we need to read the data now and register it.
|
|
|
|
|
+ _pta_id = id;
|
|
|
|
|
+ return (void *)NULL;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ return (*pi).second;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: BamReader::finalize_this
|
|
|
|
|
-// Access: Private
|
|
|
|
|
-// Description:
|
|
|
|
|
|
|
+// Function: BamReader::register_pta
|
|
|
|
|
+// Access: Public
|
|
|
|
|
+// Description: The second part of read_pta(), this should be called
|
|
|
|
|
+// with the pointer to the array that was read in after
|
|
|
|
|
+// read_pta() returned NULL. This associates the
|
|
|
|
|
+// pointer with the ID that was previously read, so that
|
|
|
|
|
+// future calls to read_pta() will return the same
|
|
|
|
|
+// pointer.
|
|
|
|
|
+//
|
|
|
|
|
+// Also see the READ_PTA() macro, which consolidates all
|
|
|
|
|
+// the work that must be done to read a PTA.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void BamReader::
|
|
void BamReader::
|
|
|
-finalize_this(TypedWriteable *whom)
|
|
|
|
|
-{
|
|
|
|
|
- whom->finalize();
|
|
|
|
|
- _finalize_list.erase(whom);
|
|
|
|
|
|
|
+register_pta(void *ptr) {
|
|
|
|
|
+ if (_pta_id != -1) {
|
|
|
|
|
+ bool inserted = _ptamap.insert(PTAMap::value_type(_pta_id, ptr)).second;
|
|
|
|
|
+ _pta_id = -1;
|
|
|
|
|
+ nassertv(inserted);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: BamReader::finalize
|
|
|
|
|
|
|
+// Function: BamReader::p_read_object
|
|
|
// Access: Private
|
|
// Access: Private
|
|
|
-// Description: Call finalize_this on all objects stored
|
|
|
|
|
|
|
+// Description: The private implementation of read_object(), this
|
|
|
|
|
+// reads an object from the file and returns its object
|
|
|
|
|
+// ID.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-void BamReader::
|
|
|
|
|
-finalize(void)
|
|
|
|
|
-{
|
|
|
|
|
-#ifndef NDEBUG
|
|
|
|
|
- if (bam_cat.is_debug()) {
|
|
|
|
|
- bam_cat.debug()
|
|
|
|
|
- << "Finalizing bam source\n";
|
|
|
|
|
|
|
+int BamReader::
|
|
|
|
|
+p_read_object() {
|
|
|
|
|
+ Datagram packet;
|
|
|
|
|
+
|
|
|
|
|
+ if (_source->is_error()) {
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
-#endif
|
|
|
|
|
|
|
|
|
|
- Finalize::iterator fi = _finalize_list.begin();
|
|
|
|
|
- while(fi != _finalize_list.end())
|
|
|
|
|
- {
|
|
|
|
|
- if (*fi == TypedWriteable::Null)
|
|
|
|
|
- {
|
|
|
|
|
- bam_cat.error() << "Spun off into the weeds. "
|
|
|
|
|
- << "somehow a null was registered to be "
|
|
|
|
|
- << "finalized." << endl;
|
|
|
|
|
- _finalize_list.erase(fi);
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- finalize_this(*fi);
|
|
|
|
|
|
|
+ // First, read a datagram for the object.
|
|
|
|
|
+ if (!_source->get_datagram(packet)) {
|
|
|
|
|
+ // When we run out of datagrams, we're at the end of the file.
|
|
|
|
|
+
|
|
|
|
|
+#ifndef NDEBUG
|
|
|
|
|
+ if (bam_cat.is_debug()) {
|
|
|
|
|
+ bam_cat.debug()
|
|
|
|
|
+ << "Reached end of bam source.\n";
|
|
|
}
|
|
}
|
|
|
- fi = _finalize_list.begin();
|
|
|
|
|
|
|
+#endif
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-// Function: BamReader::get_pta
|
|
|
|
|
-// Access: Public
|
|
|
|
|
-// Description: Requests an already read PTA from BamReader. If
|
|
|
|
|
-// the PTA has not already been read and registered,
|
|
|
|
|
-// returns a NULL
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-void* BamReader::
|
|
|
|
|
-get_pta(DatagramIterator &scan)
|
|
|
|
|
-{
|
|
|
|
|
- int _id = scan.get_uint16();
|
|
|
|
|
|
|
+ // Now extract the object definition from the datagram.
|
|
|
|
|
+ DatagramIterator scan(packet);
|
|
|
|
|
|
|
|
- if (_id == 0)
|
|
|
|
|
- {
|
|
|
|
|
- _pta_id = -1;
|
|
|
|
|
- return (void*)NULL;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // An object definition in a Bam file consists of a TypeHandle
|
|
|
|
|
+ // definition, defining the object's type, followed by an object ID
|
|
|
|
|
+ // index, defining the particular instance (e.g. pointer) of this
|
|
|
|
|
+ // object.
|
|
|
|
|
|
|
|
- if (_ptamap.find(_id) == _ptamap.end())
|
|
|
|
|
- {
|
|
|
|
|
- _pta_id = _id;
|
|
|
|
|
- return (void*)NULL;
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- //Just to enforce that register_pta should do nothing if
|
|
|
|
|
- //get_pta returns a good value or a NULL was what was
|
|
|
|
|
- //actually written
|
|
|
|
|
- _pta_id = -1;
|
|
|
|
|
|
|
+ TypeHandle type = read_handle(scan);
|
|
|
|
|
+ int object_id = scan.get_uint16();
|
|
|
|
|
+
|
|
|
|
|
+ // There are two cases. Either this is a new object definition, or
|
|
|
|
|
+ // this is a reference to an object that was previously defined.
|
|
|
|
|
+
|
|
|
|
|
+ // We use the TypeHandle to differentiate these two cases. By
|
|
|
|
|
+ // convention, we write a TypeHandle::none() to the Bam file when we
|
|
|
|
|
+ // are writing a reference to a previously-defined object, but we
|
|
|
|
|
+ // write the object's actual type when we are writing its definition
|
|
|
|
|
+ // right now.
|
|
|
|
|
+
|
|
|
|
|
+ // Therefore, if the type is TypeHandle::none(), then we must have
|
|
|
|
|
+ // already read in and created the object (although its pointers may
|
|
|
|
|
+ // not be fully instantiated yet). On the other hand, if the type
|
|
|
|
|
+ // is anything else, then we must read the definition to follow.
|
|
|
|
|
+
|
|
|
|
|
+ if (type != TypeHandle::none()) {
|
|
|
|
|
+ // Now we are going to read and create a new object.
|
|
|
|
|
+
|
|
|
|
|
+ // Defined the parameters for passing to the object factory.
|
|
|
|
|
+ FactoryParams fparams;
|
|
|
|
|
+ fparams.add_param(new BamReaderParam(scan, this));
|
|
|
|
|
+
|
|
|
|
|
+ // First, we must add an entry into the map for this object ID, so
|
|
|
|
|
+ // that in case this function is called recursively during the
|
|
|
|
|
+ // object's factory constructor, we will have some definition for
|
|
|
|
|
+ // the object. It doesn't matter yet what the pointer is.
|
|
|
|
|
+ CreatedObjs::iterator oi =
|
|
|
|
|
+ _created_objs.insert(CreatedObjs::value_type(object_id, NULL)).first;
|
|
|
|
|
+
|
|
|
|
|
+ // Now we can call the factory to create the object.
|
|
|
|
|
+ TypedWriteable *object =
|
|
|
|
|
+ _factory->make_instance_more_general(type, fparams);
|
|
|
|
|
+
|
|
|
|
|
+ // And now we can store the new object pointer in the map.
|
|
|
|
|
+ (*oi).second = object;
|
|
|
|
|
+
|
|
|
|
|
+ //Just some sanity checks
|
|
|
|
|
+ if (object == (TypedWriteable *)NULL) {
|
|
|
|
|
+ bam_cat.error()
|
|
|
|
|
+ << "Unable to create an object of type " << type << endl;
|
|
|
|
|
+
|
|
|
|
|
+ } else if (object->get_type() != type) {
|
|
|
|
|
+ bam_cat.warning()
|
|
|
|
|
+ << "Attempted to create a " << type.get_name() \
|
|
|
|
|
+ << " but a " << object->get_type() \
|
|
|
|
|
+ << " was created instead." << endl;
|
|
|
|
|
+
|
|
|
|
|
+ } else {
|
|
|
|
|
+#ifndef NDEBUG
|
|
|
|
|
+ if (bam_cat.is_spam()) {
|
|
|
|
|
+ bam_cat.spam()
|
|
|
|
|
+ << "Read a " << object->get_type() << "\n";
|
|
|
|
|
+ }
|
|
|
|
|
+#endif
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- return _ptamap[_id];
|
|
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-// Function: BamReader::register_pta
|
|
|
|
|
-// Access: Public
|
|
|
|
|
-// Description: Utility function to be called by the objects reading
|
|
|
|
|
-// themselves from a Datagram. Registers a PTA with
|
|
|
|
|
-// BamReader, so that if there are any shared ptr references,
|
|
|
|
|
-// BamReader can detect and resolve those. To be used
|
|
|
|
|
-// in conjunction with get_pta
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-void BamReader::
|
|
|
|
|
-register_pta(void *ptr)
|
|
|
|
|
-{
|
|
|
|
|
- //Just a sanity check to make sure that register_pta
|
|
|
|
|
- //does nothing if get_pta has not been called first
|
|
|
|
|
- if (_pta_id != -1)
|
|
|
|
|
- {
|
|
|
|
|
- _ptamap[_pta_id] = ptr;
|
|
|
|
|
|
|
+#ifndef NDEBUG
|
|
|
|
|
+ if (bam_cat.is_spam()) {
|
|
|
|
|
+ bam_cat.spam()
|
|
|
|
|
+ << "Emptying queue.\n";
|
|
|
}
|
|
}
|
|
|
- _pta_id = -1;
|
|
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+ return object_id;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: BamReader::resolve
|
|
|
|
|
-// Access: Public
|
|
|
|
|
-// Description: Calling this function, asks BamReader to go ahead
|
|
|
|
|
-// and resolve all pointer requests that can be resolved
|
|
|
|
|
|
|
+// Function: BamReader::finalize
|
|
|
|
|
+// Access: Private
|
|
|
|
|
+// Description: Should be called after all objects have been read,
|
|
|
|
|
+// this will finalize all the objects that registered
|
|
|
|
|
+// themselves for the finalize callback.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-bool BamReader::
|
|
|
|
|
-resolve(void)
|
|
|
|
|
-{
|
|
|
|
|
- Requests::iterator whom, old;
|
|
|
|
|
- vector_ushort::iterator request;
|
|
|
|
|
- bool objReferencesComplete;
|
|
|
|
|
- vector_typedWriteable references;
|
|
|
|
|
-
|
|
|
|
|
- //Loop through the list of all objects who registered themselves as wanting
|
|
|
|
|
- //a pointer to another object to be completed
|
|
|
|
|
- whom = _deferred_pointers.begin();
|
|
|
|
|
- while(whom != _deferred_pointers.end())
|
|
|
|
|
- {
|
|
|
|
|
- //For each of those objects, loop through its list of objects that it is
|
|
|
|
|
- //interested in. If any one of those is not complete, then do nothing
|
|
|
|
|
- //for that object, as when it is passed the list of pointers, it will
|
|
|
|
|
- //expect them in a certain order and in totality.
|
|
|
|
|
- objReferencesComplete = true;
|
|
|
|
|
- references.clear();
|
|
|
|
|
- for(request = (*whom).second.begin(); request != (*whom).second.end(); request++)
|
|
|
|
|
- {
|
|
|
|
|
- //Check and see if the request was for a null pointer
|
|
|
|
|
- if (*request == 0)
|
|
|
|
|
- {
|
|
|
|
|
- references.push_back(TypedWriteable::Null);
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- //Test to see if the object requested has been created or not yet
|
|
|
|
|
- if (_created_objs.find((*request)) == _created_objs.end())
|
|
|
|
|
- {
|
|
|
|
|
- objReferencesComplete = false;
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- references.push_back(_created_objs[(*request)]);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- if (objReferencesComplete)
|
|
|
|
|
- {
|
|
|
|
|
- (*whom).first->complete_pointers(references, this);
|
|
|
|
|
- //The request list has been completed, so delete the
|
|
|
|
|
- //list froms storage
|
|
|
|
|
- //Annoying STL design flaw forces this delete trick
|
|
|
|
|
- old = whom;
|
|
|
|
|
- whom++;
|
|
|
|
|
- _deferred_pointers.erase(old);
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- // nassertv(objReferencesComplete);
|
|
|
|
|
- bam_cat.warning()
|
|
|
|
|
- << "Unable to complete " << (*whom).first->get_type() << "\n";
|
|
|
|
|
- whom++;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+void BamReader::
|
|
|
|
|
+finalize() {
|
|
|
|
|
+#ifndef NDEBUG
|
|
|
|
|
+ if (bam_cat.is_debug()) {
|
|
|
|
|
+ bam_cat.debug()
|
|
|
|
|
+ << "Finalizing bam source\n";
|
|
|
}
|
|
}
|
|
|
|
|
+#endif
|
|
|
|
|
|
|
|
- finalize();
|
|
|
|
|
|
|
+ Finalize::iterator fi = _finalize_list.begin();
|
|
|
|
|
+ while (fi != _finalize_list.end()) {
|
|
|
|
|
+ TypedWriteable *object = (*fi);
|
|
|
|
|
+ nassertv(object != (TypedWriteable *)NULL);
|
|
|
|
|
+ _finalize_list.erase(fi);
|
|
|
|
|
+ object->finalize();
|
|
|
|
|
|
|
|
- return true;
|
|
|
|
|
|
|
+ fi = _finalize_list.begin();
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
-
|
|
|