*** empty log message ***

This commit is contained in:
David Rose 2001-05-09 18:08:36 +00:00
parent 0aa0b38c5a
commit 1892ffa1d0
6 changed files with 334 additions and 273 deletions

View File

@ -32,9 +32,14 @@ TypeHandle EggData::_type_handle;
////////////////////////////////////////////////////////////////////
bool EggData::
resolve_egg_filename(Filename &egg_filename, const DSearchPath &searchpath) {
egg_filename.resolve_filename(searchpath, "egg");
egg_filename.resolve_filename(get_egg_path(), "egg");
egg_filename.resolve_filename(get_model_path(), "egg");
if (egg_filename.is_fully_qualified() && egg_filename.exists()) {
return true;
}
egg_filename.resolve_filename(searchpath, "egg") ||
egg_filename.resolve_filename(get_egg_path(), "egg") ||
egg_filename.resolve_filename(get_model_path(), "egg");
return egg_filename.exists();
}

View File

@ -45,7 +45,8 @@ BamReader::
// Function: BamReader::init
// Access: Public
// Description: Initializes the BamReader prior to reading any
// objects from its source.
// objects from its source. This includes reading the
// Bam header.
//
// This returns true if the BamReader successfully
// initialized, false otherwise.
@ -277,7 +278,7 @@ 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
// particular TypeHandle for the first time, 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.
@ -291,15 +292,6 @@ read_handle(DatagramIterator &scan) {
if (id == 0) {
// Index number 0 is always, by convention, TypeHandle::none().
// 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();
}
@ -309,13 +301,6 @@ read_handle(DatagramIterator &scan) {
// no type definition following the id. Simply return the
// TypeHandle we previously associated with the id.
TypeHandle type = (*mi).second;
#ifndef NDEBUG
if (bam_cat.is_spam()) {
bam_cat.spam()
<< "Read TypeHandle for " << type << ".\n";
}
#endif
return type;
}
@ -510,8 +495,8 @@ get_pta(DatagramIterator &scan) {
return (void *)NULL;
}
PTAMap::iterator pi = _ptamap.find(id);
if (pi == _ptamap.end()) {
PTAMap::iterator pi = _pta_map.find(id);
if (pi == _pta_map.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;
@ -537,7 +522,7 @@ get_pta(DatagramIterator &scan) {
void BamReader::
register_pta(void *ptr) {
if (_pta_id != -1) {
bool inserted = _ptamap.insert(PTAMap::value_type(_pta_id, ptr)).second;
bool inserted = _pta_map.insert(PTAMap::value_type(_pta_id, ptr)).second;
_pta_id = -1;
nassertv(inserted);
}
@ -640,13 +625,6 @@ p_read_object() {
}
}
#ifndef NDEBUG
if (bam_cat.is_spam()) {
bam_cat.spam()
<< "Emptying queue.\n";
}
#endif
return object_id;
}

View File

@ -18,7 +18,7 @@
#include <algorithm>
//Useful define for reading pta's
// A handy macro for reading PointerToArrays.
#define READ_PTA(Manager, source, Read_func, array) \
{ \
void *t; \
@ -44,7 +44,8 @@
// that inherits, directly or indirectly, from
// TypedWriteable. The objects may include pointers to
// other objects within the Bam file; the BamReader
// automatically manages these and restores the pointers
// automatically manages these (with help from code
// within each class) and restores the pointers
// correctly.
//
// This is the abstract interface and does not
@ -148,7 +149,7 @@ private:
// These are used by get_pta() and register_pta() to unify multiple
// references to the same PointerToArray.
typedef map<int, void *> PTAMap;
PTAMap _ptamap;
PTAMap _pta_map;
int _pta_id;
int _file_major, _file_minor;

View File

@ -1,17 +1,3 @@
// Filename: bamWriter.I
// Created by: jason (08Jun00)
//
////////////////////////////////////////////////////////////////////
// Function: BamWriter::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE BamWriter::
BamWriter(DatagramSink *sink) :
//_current needs to start from 1, as a value of 0
//for a unique object ID will be used to indicate a null pointer
_target(sink), _writing(false), _current(1),
_current_pta(1), _emptying(false)
{
}

View File

@ -10,59 +10,43 @@
#include "bamWriter.h"
////////////////////////////////////////////////////////////////////
// Function: BamWriter::Destructor
// Function: BamWriter::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
BamWriter::~BamWriter(void)
BamWriter::
BamWriter(DatagramSink *sink) :
_target(sink)
{
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::write_handle
// Function: BamWriter::Destructor
// Access: Public
// Description: Writes a type handle into the file. If the handle
// has already been encountered then a number
// identifying that handle is written instead.
// Description:
////////////////////////////////////////////////////////////////////
void BamWriter::
write_handle(Datagram &packet, TypeHandle type)
{
//No class should have a type handle index of 0
nassertv(type.get_index() != 0);
packet.add_uint16(type.get_index());
if (_type_map.find(type.get_index()) == _type_map.end())
{
// This is the first time this TypeHandle has been written, so
// also write out its name.
_type_map.insert(type.get_index());
packet.add_string(type.get_name());
// We also need to write the derivation of the TypeHandle, in case
// the program reading this file later has never heard of this
// type before.
int num_parent_classes = type.get_num_parent_classes();
nassertv(num_parent_classes <= 255); // Good grief!
packet.add_uint8(num_parent_classes);
for (int i = 0; i < num_parent_classes; i++) {
write_handle(packet, type.get_parent_class(i));
}
}
BamWriter::
~BamWriter() {
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::init
// Access: Public
// Description: This function initializes the BamWriter, setting
// up whatever needs to be set up before the BamWriter
// is ready to write out objects. It returns true if
// successful, false on failure.
// Description: Initializes the BamWriter prior to writing any
// objects to its output stream. This includes writing
// out the Bam header.
//
// This returns true if the BamWriter successfully
// initialized, false otherwise.
////////////////////////////////////////////////////////////////////
bool BamWriter::
init(void)
{
//Write out the current major and minor BAM file version numbers
init() {
// Initialize the next object and PTA ID's. These start counting at
// 1, since 0 is reserved for NULL.
_next_object_id = 1;
_next_pta_id = 1;
// Write out the current major and minor BAM file version numbers.
Datagram header;
header.add_uint16(_bam_major_ver);
@ -79,205 +63,279 @@ init(void)
////////////////////////////////////////////////////////////////////
// Function: BamWriter::write_object
// Access: Public
// Description: Main function for performing the processing of
// writing an object to some Binary target. Combined
// with write_pointer this function can correctly handle
// and break circular references, while still writing out
// the necessary information for re-constructing those
// references when the objects are read back in.
// Description: Writes a single object to the Bam file, so that the
// BamReader::read_object() can later correctly restore
// the object and all its pointers.
//
// This implicitly also writes any additional objects
// this object references (if they haven't already been
// written), so that pointers may be fully resolved.
//
// This may be called repeatedly to write a sequence of
// objects to the Bam file, but typically (especially
// for scene graph files, indicated with the .bam
// extension), only one object is written directly from
// the Bam file: the root of the scene graph. The
// remaining objects will all be written recursively by
// the first object.
//
// Returns true if the object is successfully written,
// false otherwise.
////////////////////////////////////////////////////////////////////
bool BamWriter::
write_object(TypedWriteable* obj)
{
Datagram objData;
write_object(TypedWriteable *object) {
nassertr(_object_queue.empty(), false);
nassertr(obj != TypedWriteable::Null, false);
int object_id = enqueue_object(object);
nassertr(object_id != 0, false);
//No object should ever be written out that is not
//registered as a child of TypedWriteable. The
//only way this can get in here and have that true is
//if someone forgot to set the classes init_type correctly.
//So nassert on that to make it easy for them to track
//down the error, because that will be an error, but one
//that won't show up on the writing, it will show up in
//reading, so could be potentially difficult to track down
nassertr(obj->is_of_type(TypedWriteable::get_class_type()), false);
// Now we write out all the objects in the queue, in order. The
// first one on the queue will, of course, be this object we just
// queued up, but each object we write may append more to the queue.
while (!_object_queue.empty()) {
object = _object_queue.front();
_object_queue.pop_front();
//Need to keep track of the state of any objects written
//or queued. So every time write_object is called,
//check to see if has been encountered before, if not
//insert it into a map with a Key of the pointer to
//the object and the value being a class that contains
//the unigue object ID for that object and a flag of
//whether it has been written yet or no
if (_statemap.find(obj) == _statemap.end())
{
//If the object is not already in the map, then
//add it and assign it and unique object number
_statemap[obj].objId = _current;
_current++;
//We are making the assumption that there will never
//be more than the max of an unsigned short in objects
//in one file, but just in case, this nassert will make
//it easy to find that possible error
nassertr(_current != 0, false);
}
// Look up the object in the map. It had better be there!
StateMap::iterator si = _state_map.find(object);
nassertr(si != _state_map.end(), false);
bool okflag = true;
int object_id = (*si).second._object_id;
bool already_written = (*si).second._written;
if (_writing)
{
enqueue(obj);
}
else
{
_writing = true;
Datagram dg;
if (!_statemap[obj].written)
{
//Write the type handle of the object
write_handle(objData, obj->get_type());
//Write the unique ID of the object into the datagram
//so that when it is read back, and there is a back
//reference to this object, we know what indices correspond
//to what objects
objData.add_uint16(_statemap[obj].objId);
obj->write_datagram(this, objData);
_statemap[obj].written = true;
}
else
{
//If it is in the map, then we don't want to try
//and write it again, so write the unique ID of the
//object into the datagram so that when we read in
//later, we can resolve back references. Write
//0 for the type handle to identify back references
objData.add_uint16(0);
objData.add_uint16(_statemap[obj].objId);
if (!already_written) {
// The first time we write a particular object, we do so by
// writing its TypeHandle (which had better not be
// TypeHandle::none(), since that's our code for a
// previously-written object), followed by the object ID number,
// followed by the object definition.
TypeHandle type = object->get_type();
nassertr(type != TypeHandle::none(), false);
write_handle(dg, type);
dg.add_uint16(object_id);
object->write_datagram(this, dg);
(*si).second._written = true;
} else {
// On subsequent times when we write a particular object, we
// write simply TypeHandle::none(), followed by the object ID.
// The occurrence of TypeHandle::none() is an indicator to the
// BamReader that this is a previously-written object.
write_handle(dg, TypeHandle::none());
dg.add_uint16(object_id);
}
if (!_target->put_datagram(objData)) {
if (!_target->put_datagram(dg)) {
util_cat.error()
<< "Unable to write datagram to file.\n";
okflag = false;
}
_writing = false;
if (!_emptying)
{
if (!empty_queue()) {
okflag = false;
}
return false;
}
}
return okflag;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::write_pointer
// Access: Public
// Description: Utility function to be called by the objects writing
// themselves to a Datagram. Basically amounts to a
// request to BamWriter to queue an object to be written
// and to write into the Datagram the necessary information
// to reference that object
// Description: The interface for writing a pointer to another object
// to a Bam file. This is intended to be called by the
// various objects that write themselves to the Bam
// file, within the write_datagram() method.
//
// This writes the pointer out in such a way that the
// BamReader will be able to restore the pointer later.
// If the pointer is to an object that has not yet
// itself been written to the Bam file, that object will
// automatically be written.
////////////////////////////////////////////////////////////////////
void BamWriter::
write_pointer(Datagram &packet , TypedWriteable *dest)
{
//Write a zero for the object ID if the pointer is null
if (dest == TypedWriteable::Null)
{
write_pointer(Datagram &packet, TypedWriteable *object) {
// If the pointer is NULL, we always simply write a zero for an
// object ID and leave it at that.
if (object == (TypedWriteable *)NULL) {
packet.add_uint16(0);
}
else
{
if (_statemap.find(dest) == _statemap.end())
{
write_object(dest);
} else {
StateMap::iterator si = _state_map.find(object);
if (si == _state_map.end()) {
// We have not written this pointer out yet. This means we must
// queue the object definition up for later.
int object_id = enqueue_object(object);
packet.add_uint16(object_id);
} else {
// We have already assigned this pointer an ID; thus, we can
// simply write out the ID.
packet.add_uint16((*si).second._object_id);
}
packet.add_uint16(_statemap[dest].objId);
}
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::register_pta
// Access: Public
// Description: Utility function to be called by the objects writing
// themselves to a Datagram. Registers a PTA to be written
// into the Datagram, and allows for shared references
// to be captured in the datagram
// Description: Prepares to write a PointerToArray to the Bam file,
// unifying references to the same pointer across the
// Bam file.
//
// The writing object should call this prior to writing
// out a PointerToArray. It will return true if the
// same pointer has been previously, in which case the
// writing object need do nothing further; or it will
// return false if this particular pointer has not yet
// been written, in which case the writing object must
// then write out the contents of the array.
//
// Also see the WRITE_PTA() macro, which consolidates
// the work that must be done to write a PTA.
////////////////////////////////////////////////////////////////////
bool BamWriter::
register_pta(Datagram &packet, void *ptr)
{
if (ptr != (void*)NULL)
{
if (_ptamap.find(ptr) == _ptamap.end())
{
_ptamap[ptr] = _current_pta;
packet.add_uint16(_current_pta);
_current_pta++;
return false;
}
packet.add_uint16(_ptamap[ptr]);
}
else
{
//A zero for the PTA ID indicates a NULL ptr
register_pta(Datagram &packet, void *ptr) {
if (ptr == (void *)NULL) {
// A zero for the PTA ID indicates a NULL pointer. This is a
// special case.
packet.add_uint16(0);
// We return false to indicate the user must now write out the
// "definition" of the NULL pointer. This is necessary because of
// a quirk in the BamReader's design, which forces callers to read
// the definition of every NULL pointer. Presumably, the caller
// will be able to write the definition in a concise way that will
// clearly indicate a NULL pointer; in the case of a
// PointerToArray, this will generally be simply a zero element
// count.
return false;
}
return true;
PTAMap::iterator pi = _pta_map.find(ptr);
if (pi == _pta_map.end()) {
// We have not encountered this pointer before.
int pta_id = _next_pta_id;
_next_pta_id++;
// Make sure our PTA ID will fit within the PN_uint16 we have
// allocated for it.
nassertr(pta_id <= 65535, 0);
bool inserted = _pta_map.insert(PTAMap::value_type(ptr, pta_id)).second;
nassertr(inserted, false);
packet.add_uint16(pta_id);
// Return false to indicate the caller must now write out the
// array definition.
return false;
} else {
// We have encountered this pointer before.
int pta_id = (*pi).second;
packet.add_uint16(pta_id);
// Return true to indicate the caller need do nothing further.
return true;
}
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::enqueue
// Access: Private
// Description: Queue an object to be written
// Function: BamWriter::write_handle
// Access: Public
// Description: Writes a TypeHandle to the file in such a way that
// the BamReader can read the same TypeHandle later via
// read_handle().
////////////////////////////////////////////////////////////////////
void BamWriter::
enqueue(TypedWriteable *obj)
{
_deferred.push_back(obj);
}
write_handle(Datagram &packet, TypeHandle type) {
// 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 time, 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.
////////////////////////////////////////////////////////////////////
// Function: BamWriter::empty_queue
// Access: Private
// Description: For each object in the queue call write_object on it.
// Returns true of all write_object calls returned true,
// false otherwise.
////////////////////////////////////////////////////////////////////
bool BamWriter::
empty_queue(void)
{
_emptying = true;
bool okflag = true;
while(!_deferred.empty())
{
if (!write_object(_deferred.front())) {
okflag = false;
// The unique number we choose is actually the internal index number
// of the TypeHandle. Why not?
int index = type.get_index();
// Also make sure the index number fits within a PN_uint16.
nassertv(index <= 65535);
packet.add_uint16(index);
if (index != 0) {
bool inserted = _types_written.insert(index).second;
if (inserted) {
// This is the first time this TypeHandle has been written, so
// also write out its definition.
packet.add_string(type.get_name());
// We also need to write the derivation of the TypeHandle, in case
// the program reading this file later has never heard of this
// type before.
int num_parent_classes = type.get_num_parent_classes();
nassertv(num_parent_classes <= 255); // Good grief!
packet.add_uint8(num_parent_classes);
for (int i = 0; i < num_parent_classes; i++) {
write_handle(packet, type.get_parent_class(i));
}
}
_deferred.pop_front();
}
_emptying = false;
return okflag;
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::enqueue_object
// Access: Private
// Description: Assigns an object ID to the object and queues it up
// for later writing to the Bam file.
//
// The return value is the object ID, or 0 if there is
// an error.
////////////////////////////////////////////////////////////////////
int BamWriter::
enqueue_object(TypedWriteable *object) {
Datagram dg;
nassertr(object != TypedWriteable::Null, 0);
// No object should ever be written out that is not registered as a
// child of TypedWriteable. The only way this can happen is if
// someone failed to initialize their type correctly in init_type().
nassertr(object->is_of_type(TypedWriteable::get_class_type()), 0);
// We need to assign a unique index number to every object we write
// out. Has this object been assigned a number yet?
int object_id;
bool already_written;
StateMap::iterator si = _state_map.find(object);
if (si == _state_map.end()) {
// No, it hasn't, so assign it the next number in sequence
// arbitrarily.
object_id = _next_object_id;
already_written = false;
// Make sure our object ID will fit within the PN_uint16 we have
// allocated for it.
nassertr(object_id <= 65535, 0);
bool inserted =
_state_map.insert(StateMap::value_type(object, StoreState(_next_object_id))).second;
nassertr(inserted, false);
_next_object_id++;
} else {
// Yes, it has; get the object ID.
object_id = (*si).second._object_id;
already_written = (*si).second._written;
}
_object_queue.push_back(object);
return object_id;
}

View File

@ -12,6 +12,7 @@
#include "datagramSink.h"
#include <deque>
// A handy macro for writing PointerToArrays.
#define WRITE_PTA(Manager, dest, Write_func, array) \
if (!Manager->register_pta(dest, array.p())) \
{ \
@ -21,60 +22,92 @@
////////////////////////////////////////////////////////////////////
// Class : BamWriter
// Description : This class manages all aspects of writing data
// structures to some Binary form. It writes to a
// a DatagramSink which is an abstraction that could
// be a file, the net, etc... The two basic functions
// used are write_object and write_pointer. write_object
// is called to write any TypedWriteable object out.
// BamWriter actually asks the object passed to write
// itself out to a datagram, and then it writes that
// datagram to the DatagramSink. write_pointer is called
// by the objects themselves to resolve writing out
// pointers to other objects. BamWriter will handle all
// circular references correctly
// Description : This is the fundamental interface for writing binary
// objects to a Bam file, to be extracted later by a
// BamReader.
//
// A Bam file can be thought of as a linear collection
// of objects. Each object is an instance of a class
// that inherits, directly or indirectly, from
// TypedWriteable. The objects may include pointers to
// other objects; the BamWriter automatically manages
// these (with help from code within each class) and
// writes all referenced objects to the file in such a
// way that the pointers may be correctly restored
// later.
//
// This is the abstract interface and does not
// specifically deal with disk files, but rather with a
// DatagramSink of some kind, which simply accepts a
// linear stream of Datagrams. It is probably written
// to a disk file, but it might conceivably be streamed
// directly to a network or some such nonsense.
//
// Bam files are most often used to store scene graphs
// or subgraphs, and by convention they are given
// filenames ending in the extension ".bam" when they
// are used for this purpose. However, a Bam file may
// store any arbitrary list of TypedWriteable objects;
// in this more general usage, they are given filenames
// ending in ".boo" to differentiate them from the more
// common scene graph files.
//
// See also BamFile, which defines a higher-level
// interface to read and write Bam files on disk.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA BamWriter{
public:
INLINE BamWriter(DatagramSink *sink);
~BamWriter(void);
BamWriter(DatagramSink *sink);
~BamWriter();
// The primary interface for a caller.
bool init(void);
bool init();
bool write_object(TypedWriteable *obj);
public:
// Functions to support classes that write themselves to the Bam.
void write_pointer(Datagram &packet, TypedWriteable *dest);
//This function is provided for writing out shared pointers
//to PTA's. You should pass in a pointer to the PTA you want
//to write. If BamWriter has not already been asked to register
//this pointer, it will register it, write the appropriate info
//into the Datagram and return false. If it has, it will write
//the reference into the Datagram and return true. If false is
//returned, then the class registering the PTA should write out
//the info into the Datagram itself
bool register_pta(Datagram &packet, void* ptr);
bool register_pta(Datagram &packet, void *ptr);
void write_handle(Datagram &packet, TypeHandle type);
private:
class storeState {
int enqueue_object(TypedWriteable *object);
// This is the set of all TypeHandles already written.
set<int> _types_written;
// This keeps track of all of the objects we have written out
// already (or are about to write out), and associates a unique
// object ID number to each one.
class StoreState {
public:
PN_uint16 objId;
bool written;
int _object_id;
bool _written;
storeState(void) : objId(0), written(false) {}
~storeState(void) {}
StoreState(int object_id) : _object_id(object_id), _written(false) {}
};
void enqueue(TypedWriteable *obj);
bool empty_queue(void);
typedef map<TypedWriteable *, StoreState> StateMap;
StateMap _state_map;
// This is the next object ID that will be assigned to a new object.
int _next_object_id;
// This is the queue of objects that need to be written when the
// current object is finished.
typedef deque<TypedWriteable *> ObjectQueue;
ObjectQueue _object_queue;
// These are used by register_pta() to unify multiple references to
// the same PointerToArray.
typedef map<void *, int> PTAMap;
PTAMap _pta_map;
int _next_pta_id;
// The destination to write all the output to.
DatagramSink *_target;
bool _writing;
deque<TypedWriteable*> _deferred;
set<int> _type_map;
map<TypedWriteable*, storeState> _statemap;
map<void*, int> _ptamap;
PN_uint16 _current, _current_pta;
bool _emptying;
};
#include "bamWriter.I"