merge dev_bam_2009 to trunk

This commit is contained in:
David Rose 2009-06-10 17:54:40 +00:00
parent f5f0c5ad83
commit aefe3d35c2
87 changed files with 2303 additions and 687 deletions

View File

@ -0,0 +1,24 @@
#define BUILDING_DLL BUILDING_CFTALK
#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
dtoolutil:c dtoolbase:c dtool:m prc:c
#begin lib_target
#define TARGET cftalk
#define LOCAL_LIBS \
gsgbase gobj display \
putil linmath mathutil pnmimage
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
#define SOURCES \
config_cftalk.h \
cfChannel.h cfChannel.I \
cfCommand.h cfCommand.I
#define INCLUDED_SOURCES \
cfChannel.cxx \
cfCommand.cxx
#end lib_target

View File

@ -0,0 +1,14 @@
// Filename: cfChannel.I
// Created by: drose (26Mar09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,75 @@
// Filename: cfChannel.cxx
// Created by: drose (26Mar09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "cfChannel.h"
////////////////////////////////////////////////////////////////////
// Function: CFChannel::Constructor
// Access: Public
// Description: The DatagramGenerator and DatagramSink should be
// newly created on the free store (via the new
// operator). The CFChannel will take ownership of
// these pointers, and will delete them when it
// destructs.
////////////////////////////////////////////////////////////////////
CFChannel::
CFChannel(DatagramGenerator *dggen, DatagramSink *dgsink) :
_dggen(dggen),
_dgsink(dgsink),
_reader(dggen),
_writer(dgsink)
{
bool ok1 = _reader.init();
bool ok2 = _writer.init();
nassertv(ok1 && ok2);
}
////////////////////////////////////////////////////////////////////
// Function: CFChannel::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CFChannel::
~CFChannel() {
delete _dggen;
delete _dgsink;
}
////////////////////////////////////////////////////////////////////
// Function: CFChannel::send_command
// Access: Public
// Description: Delivers a single command to the process at the other
// end of the channel.
////////////////////////////////////////////////////////////////////
void CFChannel::
send_command(CFCommand *command) {
bool ok = _writer.write_object(command);
nassertv(ok);
}
////////////////////////////////////////////////////////////////////
// Function: CFChannel::receive_command
// Access: Public
// Description: Receives a single command from the process at the other
// end of the channel. If no command is ready, the
// thread will block until one is. Returns NULL when
// the connection has been closed.
////////////////////////////////////////////////////////////////////
PT(CFCommand) CFChannel::
receive_command() {
TypedWritable *obj = _reader.read_object();
CFCommand *command;
DCAST_INTO_R(command, obj, NULL);
return command;
}

View File

@ -0,0 +1,47 @@
// Filename: cfChannel.h
// Created by: drose (26Mar09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef CFCHANNEL_H
#define CFCHANNEL_H
#include "pandabase.h"
#include "referenceCount.h"
#include "bamReader.h"
#include "bamWriter.h"
#include "cfCommand.h"
////////////////////////////////////////////////////////////////////
// Class : CFChannel
// Description : Represents an open communication channel in the
// connected-frame protocol. Commands may be sent and
// received on this channel.
////////////////////////////////////////////////////////////////////
class EXPCL_CFTALK CFChannel : public ReferenceCount {
public:
CFChannel(DatagramGenerator *dggen, DatagramSink *dgsink);
~CFChannel();
void send_command(CFCommand *command);
PT(CFCommand) receive_command();
private:
DatagramGenerator *_dggen;
DatagramSink *_dgsink;
BamReader _reader;
BamWriter _writer;
};
#include "cfChannel.I"
#endif

View File

@ -0,0 +1,51 @@
// Filename: cfCommand.I
// Created by: drose (19Feb09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: CFCommand::Constructor
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
INLINE CFCommand::
CFCommand() {
}
////////////////////////////////////////////////////////////////////
// Function: CFDoCullCommand::Constructor
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
INLINE CFDoCullCommand::
CFDoCullCommand() {
}
////////////////////////////////////////////////////////////////////
// Function: CFDoCullCommand::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE CFDoCullCommand::
CFDoCullCommand(PandaNode *scene) : _scene(scene) {
}
////////////////////////////////////////////////////////////////////
// Function: CFDoCullCommand::get_scene
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE PandaNode *CFDoCullCommand::
get_scene() const {
return _scene;
}

View File

@ -0,0 +1,113 @@
// Filename: cfCommand.cxx
// Created by: drose (19Feb09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "cfCommand.h"
TypeHandle CFCommand::_type_handle;
TypeHandle CFDoCullCommand::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: CFCommand::Destructor
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
CFCommand::
~CFCommand() {
}
////////////////////////////////////////////////////////////////////
// Function: CFDoCullCommand::register_with_read_factory
// Access: Public, Static
// Description: Tells the BamReader how to create objects of type
// CFDoCullCommand.
////////////////////////////////////////////////////////////////////
void CFDoCullCommand::
register_with_read_factory() {
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
////////////////////////////////////////////////////////////////////
// Function: CFDoCullCommand::write_datagram
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
void CFDoCullCommand::
write_datagram(BamWriter *manager, Datagram &dg) {
TypedWritable::write_datagram(manager, dg);
manager->write_pointer(dg, _scene);
}
////////////////////////////////////////////////////////////////////
// Function: CFDoCullCommand::update_bam_nested
// Access: Public, Virtual
// Description: Called by the BamWriter when this object has not
// itself been modified recently, but it should check
// its nested objects for updates.
////////////////////////////////////////////////////////////////////
void CFDoCullCommand::
update_bam_nested(BamWriter *manager) {
manager->consider_update(_scene);
}
////////////////////////////////////////////////////////////////////
// Function: CFDoCullCommand::complete_pointers
// Access: Public, Virtual
// Description: Receives an array of pointers, one for each time
// manager->read_pointer() was called in fillin().
// Returns the number of pointers processed.
////////////////////////////////////////////////////////////////////
int CFDoCullCommand::
complete_pointers(TypedWritable **p_list, BamReader *manager) {
int pi = TypedWritable::complete_pointers(p_list, manager);
PandaNode *scene;
DCAST_INTO_R(scene, p_list[pi++], pi);
_scene = scene;
return pi;
}
////////////////////////////////////////////////////////////////////
// Function: CFDoCullCommand::make_from_bam
// Access: Protected, Static
// Description: This function is called by the BamReader's factory
// when a new object of type CFDoCullCommand is encountered
// in the Bam file. It should create the CFDoCullCommand
// and extract its information from the file.
////////////////////////////////////////////////////////////////////
TypedWritable *CFDoCullCommand::
make_from_bam(const FactoryParams &params) {
CFDoCullCommand *node = new CFDoCullCommand;
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
node->fillin(scan, manager);
return node;
}
////////////////////////////////////////////////////////////////////
// Function: CFDoCullCommand::fillin
// Access: Protected
// Description: This internal function is called by make_from_bam to
// read in all of the relevant data from the BamFile for
// the new CFDoCullCommand.
////////////////////////////////////////////////////////////////////
void CFDoCullCommand::
fillin(DatagramIterator &scan, BamReader *manager) {
TypedWritable::fillin(scan, manager);
manager->read_pointer(scan);
}

View File

@ -0,0 +1,103 @@
// Filename: cfCommand.h
// Created by: drose (19Feb09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef CFCOMMAND_H
#define CFCOMMAND_H
#include "pandabase.h"
#include "typedWritableReferenceCount.h"
#include "pandaNode.h"
////////////////////////////////////////////////////////////////////
// Class : CFCommand
// Description : A single command in the Connected-Frame protocol.
// This can be sent client-to-server or
// server-to-client.
//
// This is an abstract base class. Individual commands
// will specialize from this.
////////////////////////////////////////////////////////////////////
class EXPCL_CFTALK CFCommand : public TypedWritableReferenceCount {
protected:
CFCommand();
PUBLISHED:
virtual ~CFCommand();
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
TypedWritableReferenceCount::init_type();
register_type(_type_handle, "CFCommand",
TypedWritableReferenceCount::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
////////////////////////////////////////////////////////////////////
// Class : CFDoCullCommand
// Description : Starts the cull process for a particular
// DisplayRegion.
////////////////////////////////////////////////////////////////////
class EXPCL_CFTALK CFDoCullCommand : public CFCommand {
protected:
INLINE CFDoCullCommand();
PUBLISHED:
INLINE CFDoCullCommand(PandaNode *scene);
INLINE PandaNode *get_scene() const;
private:
PT(PandaNode) _scene;
public:
static void register_with_read_factory();
virtual void write_datagram(BamWriter *manager, Datagram &dg);
virtual void update_bam_nested(BamWriter *manager);
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);
void fillin(DatagramIterator &scan, BamReader *manager);
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
CFCommand::init_type();
register_type(_type_handle, "CFDoCullCommand",
CFCommand::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#include "cfCommand.I"
#endif

View File

@ -0,0 +1 @@
#include "cfCommand.cxx"

View File

@ -0,0 +1 @@
#include "cfChannel.cxx"

View File

@ -0,0 +1,49 @@
// Filename: config_cftalk.cxx
// Created by: drose (26Mar09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "config_cftalk.h"
#include "cfCommand.h"
#include "pandaSystem.h"
ConfigureDef(config_cftalk);
NotifyCategoryDef(cftalk, "");
ConfigureFn(config_cftalk) {
init_libcftalk();
}
////////////////////////////////////////////////////////////////////
// Function: init_libcftalk
// Description: Initializes the library. This must be called at
// least once before any of the functions or classes in
// this library can be used. Normally it will be
// called by the static initializers and need not be
// called explicitly, but special cases exist.
////////////////////////////////////////////////////////////////////
void
init_libcftalk() {
static bool initialized = false;
if (initialized) {
return;
}
initialized = true;
CFCommand::init_type();
CFDoCullCommand::init_type();
CFDoCullCommand::register_with_read_factory();
PandaSystem *ps = PandaSystem::get_global_ptr();
ps->add_system("cftalk");
}

View File

@ -0,0 +1,37 @@
// Filename: config_cftalk.h
// Created by: drose (26Mar09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef CONFIG_CFTALK_H
#define CONFIG_CFTALK_H
#include "pandabase.h"
#include "windowProperties.h"
#include "notifyCategoryProxy.h"
#include "configVariableBool.h"
#include "configVariableString.h"
#include "configVariableList.h"
#include "configVariableInt.h"
#include "configVariableEnum.h"
#include "configVariableFilename.h"
#include "coordinateSystem.h"
#include "dconfig.h"
#include "pvector.h"
ConfigureDecl(config_cftalk, EXPCL_CFTALK, EXPTP_CFTALK);
NotifyCategoryDecl(cftalk, EXPCL_CFTALK, EXPTP_CFTALK);
extern EXPCL_CFTALK void init_libcftalk();
#endif /* CONFIG_CFTALK_H */

View File

@ -12,7 +12,6 @@
//
////////////////////////////////////////////////////////////////////
#include "config_display.h"
#include "displayRegion.h"
#include "displayRegionCullCallbackData.h"

View File

@ -788,7 +788,7 @@ create_texture(DXScreenData &scrn) {
BamCache *cache = BamCache::get_global_ptr();
PT(BamCacheRecord) record = cache->lookup(tex->get_fullpath(), "txo");
if (record != (BamCacheRecord *)NULL) {
record->set_data(tex, false);
record->set_data(tex, tex);
cache->store(record);
}
}

View File

@ -938,7 +938,7 @@ create_texture(DXScreenData &scrn) {
BamCache *cache = BamCache::get_global_ptr();
PT(BamCacheRecord) record = cache->lookup(tex->get_fullpath(), "txo");
if (record != (BamCacheRecord *)NULL) {
record->set_data(tex, false);
record->set_data(tex, tex);
cache->store(record);
}
}

View File

@ -16,9 +16,10 @@
////////////////////////////////////////////////////////////////////
// Function: DatagramSink::Destructor
// Access: Public
// Access: Public, Virtual
// Description: Does nothing since this is class is just
// the definition of an interface
////////////////////////////////////////////////////////////////////
DatagramSink::~DatagramSink(){
DatagramSink::
~DatagramSink(){
}

View File

@ -32,6 +32,7 @@ PUBLISHED:
virtual bool put_datagram(const Datagram &data) = 0;
virtual bool is_error() = 0;
virtual void flush() = 0;
};
#include "datagramSink.I"

View File

@ -88,16 +88,10 @@ operator = (const ReferenceCount &) {
////////////////////////////////////////////////////////////////////
// Function: ReferenceCount::Destructor
// Access: Protected
// Description: The ReferenceCount destructor is protected to
// discourage users from accidentally trying to delete a
// ReferenceCount pointer directly. This is almost
// always a bad idea, since the destructor is not
// virtual, and you've almost certainly got some pointer
// to something that inherits from ReferenceCount, not
// just a plain old ReferenceCount object.
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
INLINE ReferenceCount::
ReferenceCount::
~ReferenceCount() {
TAU_PROFILE("ReferenceCount::~ReferenceCount()", " ", TAU_USER);
nassertv(this != NULL);
@ -193,13 +187,12 @@ ref() const {
////////////////////////////////////////////////////////////////////
// Function: ReferenceCount::unref
// Access: Published
// Access: Published, Virtual
// Description: Explicitly decrements the reference count. Note that
// the object will not be implicitly deleted by unref()
// simply because the reference count drops to zero.
// (Having a member function delete itself is
// problematic; plus, we don't have a virtual destructor
// anyway.) However, see the helper function
// problematic.) However, see the helper function
// unref_delete().
//
// User code should avoid using ref() and unref()

View File

@ -43,12 +43,14 @@ protected:
INLINE ReferenceCount();
INLINE ReferenceCount(const ReferenceCount &);
INLINE void operator = (const ReferenceCount &);
INLINE ~ReferenceCount();
public:
virtual INLINE ~ReferenceCount();
PUBLISHED:
INLINE int get_ref_count() const;
INLINE void ref() const;
INLINE bool unref() const;
virtual INLINE bool unref() const;
INLINE bool test_ref_count_integrity() const;
INLINE bool test_ref_count_nonzero() const;

View File

@ -7691,7 +7691,7 @@ upload_texture(CLP(TextureContext) *gtc, bool force) {
BamCache *cache = BamCache::get_global_ptr();
PT(BamCacheRecord) record = cache->lookup(tex->get_fullpath(), "txo");
if (record != (BamCacheRecord *)NULL) {
record->set_data(tex, false);
record->set_data(tex, tex);
cache->store(record);
}
}

View File

@ -612,7 +612,7 @@ write_datagram(BamWriter *manager, Datagram &dg, void *extra_data) const {
dg.add_uint32(_buffer.get_size());
if (manager->get_file_endian() == BE_native) {
if (manager->get_file_endian() == BamWriter::BE_native) {
// For native endianness, we only have to write the data directly.
dg.append_data(_buffer.get_read_pointer(true), _buffer.get_size());
@ -656,7 +656,7 @@ fillin(DatagramIterator &scan, BamReader *manager, void *extra_data) {
bool endian_reversed = false;
if (manager->get_file_endian() != BE_native) {
if (manager->get_file_endian() != BamReader::BE_native) {
// For non-native endian files, we have to convert the data.
if (array_data->_array_format == (GeomVertexArrayFormat *)NULL) {

View File

@ -194,7 +194,7 @@ GeomVertexArrayFormat::
////////////////////////////////////////////////////////////////////
// Function: GeomVertexArrayFormat::unref
// Access: Published
// Access: Published, Virtual
// Description: This method overrides ReferenceCount::unref() to
// unregister the object when its reference count goes
// to zero.

View File

@ -77,7 +77,7 @@ PUBLISHED:
void operator = (const GeomVertexArrayFormat &copy);
~GeomVertexArrayFormat();
bool unref() const;
virtual bool unref() const;
INLINE bool is_registered() const;
INLINE static CPT(GeomVertexArrayFormat) register_format(const GeomVertexArrayFormat *format);

View File

@ -88,7 +88,7 @@ GeomVertexFormat::
////////////////////////////////////////////////////////////////////
// Function: GeomVertexFormat::unref
// Access: Published
// Access: Published, Virtual
// Description: This method overrides ReferenceCount::unref() to
// unregister the object when its reference count goes
// to zero.

View File

@ -66,7 +66,7 @@ PUBLISHED:
void operator = (const GeomVertexFormat &copy);
virtual ~GeomVertexFormat();
bool unref() const;
virtual bool unref() const;
INLINE bool is_registered() const;
INLINE static CPT(GeomVertexFormat) register_format(const GeomVertexFormat *format);

View File

@ -74,7 +74,7 @@ InternalName::
////////////////////////////////////////////////////////////////////
// Function: InternalName::unref
// Access: Published
// Access: Published, Virtual
// Description: This method overrides ReferenceCount::unref() to
// clear the pointer from its parent's table when
// its reference count goes to zero.

View File

@ -45,7 +45,7 @@ private:
PUBLISHED:
virtual ~InternalName();
bool unref() const;
virtual bool unref() const;
INLINE static PT(InternalName) make(const string &name);
static PT(InternalName) make(const string &name, int index);

View File

@ -3011,7 +3011,7 @@ do_write_txo(ostream &out, const string &filename) const {
return false;
}
writer.set_file_texture_mode(BTM_rawdata);
writer.set_file_texture_mode(BamWriter::BTM_rawdata);
// We have to temporarily release the lock to allow it to write
// (since the BamWriter will call write_datagram, which in turn
@ -3155,8 +3155,8 @@ do_reload_ram_image(bool allow_compression) {
record = cache->lookup(_fullpath, "txo");
if (record != (BamCacheRecord *)NULL &&
record->has_data()) {
PT(Texture) tex = DCAST(Texture, record->extract_data());
PT(Texture) tex = DCAST(Texture, record->get_data());
// But don't use the cache record if the config parameters have
// changed, and we want a different-sized texture now.
int x_size = _orig_file_x_size;
@ -3204,7 +3204,7 @@ do_reload_ram_image(bool allow_compression) {
// We've re-compressed the image after loading it from the
// cache. To keep the cache current, rewrite it to the
// cache now, in its newly compressed form.
record->set_data(this, false);
record->set_data(this, this);
cache->store(record);
}
}
@ -3250,7 +3250,7 @@ do_reload_ram_image(bool allow_compression) {
if (record != (BamCacheRecord *)NULL) {
record->add_dependent_file(_fullpath);
}
record->set_data(this, false);
record->set_data(this, this);
cache->store(record);
}
}
@ -6124,9 +6124,9 @@ write_datagram(BamWriter *manager, Datagram &me) {
// Otherwise, we just write out the filename, and assume whoever
// loads the bam file later will have access to the image file on
// disk.
BamTextureMode file_texture_mode = manager->get_file_texture_mode();
BamWriter::BamTextureMode file_texture_mode = manager->get_file_texture_mode();
bool has_rawdata =
(file_texture_mode == BTM_rawdata || (do_has_ram_image() && _filename.empty()));
(file_texture_mode == BamWriter::BTM_rawdata || (do_has_ram_image() && _filename.empty()));
if (has_rawdata && !do_has_ram_image()) {
do_get_ram_image();
if (!do_has_ram_image()) {
@ -6143,16 +6143,16 @@ write_datagram(BamWriter *manager, Datagram &me) {
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
switch (file_texture_mode) {
case BTM_unchanged:
case BTM_rawdata:
case BamWriter::BTM_unchanged:
case BamWriter::BTM_rawdata:
break;
case BTM_fullpath:
case BamWriter::BTM_fullpath:
filename = _fullpath;
alpha_filename = _alpha_fullpath;
break;
case BTM_relative:
case BamWriter::BTM_relative:
filename = _fullpath;
alpha_filename = _alpha_fullpath;
bam_dir.make_absolute(vfs->get_cwd());
@ -6174,7 +6174,7 @@ write_datagram(BamWriter *manager, Datagram &me) {
}
break;
case BTM_basename:
case BamWriter::BTM_basename:
filename = _fullpath.get_basename();
alpha_filename = _alpha_fullpath.get_basename();
break;

View File

@ -323,7 +323,7 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels,
if (store_record && tex->has_ram_image()) {
// Store the on-disk cache record for next time.
record->set_data(tex, false);
record->set_data(tex, tex);
cache->store(record);
}
@ -455,7 +455,7 @@ ns_load_texture(const Filename &orig_filename,
if (store_record && tex->has_ram_image()) {
// Store the on-disk cache record for next time.
record->set_data(tex, false);
record->set_data(tex, tex);
cache->store(record);
}
@ -563,7 +563,7 @@ ns_load_3d_texture(const Filename &filename_pattern,
if (store_record && tex->has_ram_image()) {
// Store the on-disk cache record for next time.
record->set_data(tex, false);
record->set_data(tex, tex);
cache->store(record);
}
@ -662,7 +662,7 @@ ns_load_cube_map(const Filename &filename_pattern, bool read_mipmaps,
if (store_record && tex->has_ram_image()) {
// Store the on-disk cache record for next time.
record->set_data(tex, false);
record->set_data(tex, tex);
cache->store(record);
}
@ -941,7 +941,7 @@ try_load_cache(PT(Texture) &tex, BamCache *cache, const Filename &filename,
record = cache->lookup(filename, "txo");
if (record != (BamCacheRecord *)NULL) {
if (record->has_data()) {
tex = DCAST(Texture, record->extract_data());
tex = DCAST(Texture, record->get_data());
compressed_cache_record = (tex->get_ram_image_compression() != Texture::CM_off);
int x_size = tex->get_orig_file_x_size();
int y_size = tex->get_orig_file_y_size();
@ -1002,7 +1002,7 @@ try_load_cache(PT(Texture) &tex, BamCache *cache, const Filename &filename,
// from the cache. To keep the cache current,
// rewrite it to the cache now, in its newly
// compressed form.
record->set_data(tex, false);
record->set_data(tex, tex);
cache->store(record);
compressed_cache_record = true;
}

View File

@ -567,6 +567,15 @@ process_incoming_udp_data(SocketInfo *sinfo) {
} else {
datagram.set_connection(sinfo->_connection);
datagram.set_address(NetAddress(addr));
if (net_cat.is_spam()) {
net_cat.spam()
<< "Received UDP datagram with "
<< datagram_udp_header_size + datagram.get_length()
<< " bytes on " << (void *)datagram.get_connection()
<< " from " << datagram.get_address() << "\n";
}
receive_datagram(datagram);
}
@ -683,6 +692,15 @@ process_incoming_tcp_data(SocketInfo *sinfo) {
} else {
datagram.set_connection(sinfo->_connection);
datagram.set_address(NetAddress(socket->GetPeerName()));
if (net_cat.is_spam()) {
net_cat.spam()
<< "Received TCP datagram with "
<< _tcp_header_size + datagram.get_length()
<< " bytes on " << (void *)datagram.get_connection()
<< " from " << datagram.get_address() << "\n";
}
receive_datagram(datagram);
}
@ -734,6 +752,14 @@ process_raw_incoming_udp_data(SocketInfo *sinfo) {
datagram.set_connection(sinfo->_connection);
datagram.set_address(NetAddress(addr));
if (net_cat.is_spam()) {
net_cat.spam()
<< "Received raw UDP datagram with " << datagram.get_length()
<< " bytes on " << (void *)datagram.get_connection()
<< " from " << datagram.get_address() << "\n";
}
receive_datagram(datagram);
return true;
@ -782,6 +808,14 @@ process_raw_incoming_tcp_data(SocketInfo *sinfo) {
datagram.set_connection(sinfo->_connection);
datagram.set_address(NetAddress(socket->GetPeerName()));
if (net_cat.is_spam()) {
net_cat.spam()
<< "Received raw TCP datagram with " << datagram.get_length()
<< " bytes on " << (void *)datagram.get_connection()
<< " from " << datagram.get_address() << "\n";
}
receive_datagram(datagram);
return true;

View File

@ -56,11 +56,19 @@ get_datagram(Datagram &data) {
if (is_polling()) {
// Single-threaded case: we poll. No need to lock.
if (!thing_available()) {
if (net_cat.is_spam()) {
net_cat.spam()
<< "DatagramGeneratorNet polling\n";
}
poll();
}
while (!thing_available()) {
if (is_eof()) {
return false;
if (net_cat.is_spam()) {
net_cat.spam()
<< "DatagramGeneratorNet returning EOF\n";
}
return false;
}
poll();
Thread::force_yield();
@ -74,7 +82,15 @@ get_datagram(Datagram &data) {
MutexHolder holder(_dg_lock);
while (!thing_available()) {
if (is_eof()) {
return false;
if (net_cat.is_spam()) {
net_cat.spam()
<< "DatagramGeneratorNet returning EOF\n";
}
return false;
}
if (net_cat.is_spam()) {
net_cat.spam()
<< "DatagramGeneratorNet waiting\n";
}
_dg_received.wait();
}
@ -83,6 +99,12 @@ get_datagram(Datagram &data) {
_dg_processed.notify();
}
if (net_cat.is_spam()) {
net_cat.spam()
<< "DatagramGeneratorNet returning datagram of length "
<< data.get_length() << "\n";
}
return true;
}

View File

@ -56,3 +56,16 @@ bool DatagramSinkNet::
is_error() {
return (_target == (Connection *)NULL || _target->get_socket() == (Socket_IP *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: DatagramSinkNet::flush
// Access: Public, Virtual
// Description: Ensures that all datagrams previously written will be
// visible on the stream.
////////////////////////////////////////////////////////////////////
void DatagramSinkNet::
flush() {
if (_target != (Connection *)NULL) {
_target->flush();
}
}

View File

@ -35,6 +35,7 @@ PUBLISHED:
// Inherited from DatagramSink
virtual bool put_datagram(const Datagram &data);
virtual bool is_error();
virtual void flush();
private:
PT(Connection) _target;

View File

@ -200,6 +200,14 @@
#define EXPTP_TINYDISPLAY extern
#endif
#ifdef BUILDING_CFTALK
#define EXPCL_CFTALK __declspec(dllexport)
#define EXPTP_CFTALK
#else
#define EXPCL_CFTALK __declspec(dllimport)
#define EXPTP_CFTALK extern
#endif
#else /* !WIN32_VC */
#define EXPCL_FRAMEWORK
@ -268,6 +276,9 @@
#define EXPCL_TINYDISPLAY
#define EXPTP_TINYDISPLAY
#define EXPCL_CFTALK
#define EXPTP_CFTALK
#endif /* WIN32_VC */
#if defined(WIN32_VC) && !defined(CPPPARSER)

View File

@ -200,8 +200,8 @@ read_node(bool report_errors) {
if (report_errors) {
loader_cat.error()
<< "Unable to resolve Bam file.\n";
result = (PandaNode *)NULL;
}
result = (PandaNode *)NULL;
}
return result;
@ -280,7 +280,7 @@ write_object(const TypedWritable *object) {
void BamFile::
close() {
if (_reader != (BamReader *)NULL) {
resolve();
// resolve();
delete _reader;
_reader = NULL;
}
@ -331,7 +331,7 @@ get_file_minor_ver() {
// Description: Returns the endian preference indicated by the Bam
// file currently being read or written.
////////////////////////////////////////////////////////////////////
BamEndian BamFile::
BamFile::BamEndian BamFile::
get_file_endian() const {
if (_writer != (BamWriter *)NULL) {
return _writer->get_file_endian();

View File

@ -16,11 +16,11 @@
#define BAMFILE_H
#include "pandabase.h"
#include "bamEndian.h"
#include "datagramInputFile.h"
#include "datagramOutputFile.h"
#include "pandaNode.h"
#include "pointerTo.h"
#include "bamEnums.h"
class BamReader;
class BamWriter;
@ -42,7 +42,7 @@ class Filename;
// ending in ".boo" to differentiate them from the more
// common scene graph files.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_PGRAPH BamFile {
class EXPCL_PANDA_PGRAPH BamFile : public BamEnums {
PUBLISHED:
BamFile();
~BamFile();

View File

@ -294,7 +294,7 @@ try_load_file(const Filename &pathname, const LoaderOptions &options,
loader_cat.info()
<< "Model " << pathname << " found in disk cache.\n";
}
PT(PandaNode) result = DCAST(PandaNode, record->extract_data());
PT(PandaNode) result = DCAST(PandaNode, record->get_data());
if (premunge_data) {
SceneGraphReducer sgr;
sgr.premunge(result, RenderState::make_empty());
@ -308,7 +308,7 @@ try_load_file(const Filename &pathname, const LoaderOptions &options,
PT(PandaNode) result = requested_type->load_file(pathname, options, record);
if (result != (PandaNode *)NULL){
if (record != (BamCacheRecord *)NULL) {
record->set_data(result, false);
record->set_data(result, result);
cache->store(record);
}

View File

@ -13,7 +13,6 @@
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: PandaNode::get_num_parents
// Access: Published
@ -664,6 +663,7 @@ INLINE void PandaNode::
set_final(bool flag) {
CDWriter cdata(_cycler);
cdata->_final_bounds = flag;
mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
@ -1874,3 +1874,14 @@ INLINE PandaNode::Parents PandaNodePipelineReader::
get_parents() const {
return PandaNode::Parents(_cdata);
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::BamReaderAuxDataDown::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PandaNode::BamReaderAuxDataDown::
BamReaderAuxDataDown() :
_down_list(PandaNode::get_class_type())
{
}

View File

@ -33,6 +33,8 @@
NotifyCategoryDecl(drawmask, EXPCL_PANDA_PGRAPH, EXPTP_PANDA_PGRAPH);
NotifyCategoryDef(drawmask, "");
TypeHandle PandaNode::BamReaderAuxDataDown::_type_handle;
PandaNode::SceneRootFunc *PandaNode::_scene_root_func;
PandaNodeChain PandaNode::_dirty_prev_transforms;
@ -109,12 +111,18 @@ PandaNode::
// We shouldn't have any parents left by the time we destruct, or
// there's a refcount fault somewhere.
// Actually, that's not necessarily true anymore, since we might be
// updating a node dynamically via the bam reader, which doesn't
// necessarily keep related pairs of nodes in sync with each other.
/*
#ifndef NDEBUG
{
CDReader cdata(_cycler);
nassertv(cdata->get_up()->empty());
}
#endif // NDEBUG
*/
remove_all_children();
}
@ -192,6 +200,17 @@ operator = (const PandaNode &copy) {
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::as_reference_count
// Access: Public, Virtual
// Description: Returns the pointer cast to a ReferenceCount pointer,
// if it is in fact of that type.
////////////////////////////////////////////////////////////////////
ReferenceCount *PandaNode::
as_reference_count() {
return this;
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::make_copy
// Access: Public, Virtual
@ -361,6 +380,7 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types,
}
CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
}
mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
@ -668,6 +688,8 @@ add_child(PandaNode *child_node, int sort, Thread *current_thread) {
children_changed();
child_node->parents_changed();
mark_bam_modified();
child_node->mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
@ -698,6 +720,8 @@ remove_child(int child_index, Thread *current_thread) {
children_changed();
child_node->parents_changed();
mark_bam_modified();
child_node->mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
@ -829,6 +853,8 @@ stash_child(int child_index, Thread *current_thread) {
children_changed();
child_node->parents_changed();
mark_bam_modified();
child_node->mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
@ -875,6 +901,8 @@ unstash_child(int stashed_index, Thread *current_thread) {
force_bounds_stale();
children_changed();
child_node->parents_changed();
mark_bam_modified();
child_node->mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
@ -919,6 +947,8 @@ add_stashed(PandaNode *child_node, int sort, Thread *current_thread) {
// Call callback hooks.
children_changed();
child_node->parents_changed();
mark_bam_modified();
child_node->mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
@ -947,6 +977,8 @@ remove_stashed(int child_index, Thread *current_thread) {
children_changed();
child_node->parents_changed();
mark_bam_modified();
child_node->mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
@ -973,6 +1005,7 @@ remove_all_children(Thread *current_thread) {
sever_connection(this, child_node, pipeline_stage, current_thread);
child_node->parents_changed();
child_node->mark_bam_modified();
}
down->clear();
@ -985,6 +1018,7 @@ remove_all_children(Thread *current_thread) {
sever_connection(this, child_node, pipeline_stage, current_thread);
child_node->parents_changed();
child_node->mark_bam_modified();
}
stashed.clear();
}
@ -992,6 +1026,7 @@ remove_all_children(Thread *current_thread) {
force_bounds_stale();
children_changed();
mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
@ -1091,6 +1126,7 @@ set_attrib(const RenderAttrib *attrib, int override) {
if (any_changed) {
mark_bounds_stale(current_thread);
state_changed();
mark_bam_modified();
}
}
@ -1124,6 +1160,7 @@ clear_attrib(int slot) {
if (any_changed) {
mark_bounds_stale(current_thread);
state_changed();
mark_bam_modified();
}
}
@ -1145,6 +1182,7 @@ set_effect(const RenderEffect *effect) {
cdata->set_fancy_bit(FB_effects, true);
}
CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
@ -1162,6 +1200,7 @@ clear_effect(TypeHandle type) {
cdata->set_fancy_bit(FB_effects, !cdata->_effects->is_empty());
}
CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
@ -1193,6 +1232,7 @@ set_state(const RenderState *state, Thread *current_thread) {
if (any_changed) {
mark_bounds_stale(current_thread);
state_changed();
mark_bam_modified();
}
}
@ -1214,6 +1254,7 @@ set_effects(const RenderEffects *effects, Thread *current_thread) {
cdata->set_fancy_bit(FB_effects, !effects->is_empty());
}
CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
@ -1247,6 +1288,7 @@ set_transform(const TransformState *transform, Thread *current_thread) {
if (any_changed) {
mark_bounds_stale(current_thread);
transform_changed();
mark_bam_modified();
}
}
@ -1274,6 +1316,7 @@ set_prev_transform(const TransformState *transform, Thread *current_thread) {
}
}
CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
@ -1295,6 +1338,7 @@ reset_prev_transform(Thread *current_thread) {
cdata->_prev_transform = cdata->_transform;
}
CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
@ -1327,6 +1371,7 @@ reset_all_prev_transform(Thread *current_thread) {
panda_node->_prev = NULL;
panda_node->_next = NULL;
#endif // NDEBUG
panda_node->mark_bam_modified();
}
_dirty_prev_transforms._prev = &_dirty_prev_transforms;
@ -1356,6 +1401,7 @@ set_tag(const string &key, const string &value, Thread *current_thread) {
cdata->set_fancy_bit(FB_tag, true);
}
CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
@ -1373,6 +1419,7 @@ clear_tag(const string &key, Thread *current_thread) {
cdata->set_fancy_bit(FB_tag, !cdata->_tag_data.empty());
}
CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
mark_bam_modified();
}
#ifdef HAVE_PYTHON
@ -1412,6 +1459,9 @@ set_python_tag(const string &key, PyObject *value) {
Py_XDECREF(old_value);
(*ti).second = value;
}
// Even though the python tag isn't recorded in the bam stream?
mark_bam_modified();
}
#endif // HAVE_PYTHON
@ -1478,6 +1528,9 @@ clear_python_tag(const string &key) {
Py_XDECREF(value);
cdata->_python_tag_data.erase(ti);
}
// Even though the python tag isn't recorded in the bam stream?
mark_bam_modified();
}
#endif // HAVE_PYTHON
@ -1537,6 +1590,7 @@ copy_tags(PandaNode *other) {
#endif // HAVE_PYTHON
}
CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
@ -1765,6 +1819,7 @@ copy_all_properties(PandaNode *other) {
if (any_draw_mask_changed) {
draw_mask_changed();
}
mark_bam_modified();
}
}
@ -1968,6 +2023,7 @@ adjust_draw_mask(DrawMask show_mask, DrawMask hide_mask, DrawMask clear_mask) {
if (any_changed) {
mark_bounds_stale(current_thread);
draw_mask_changed();
mark_bam_modified();
}
}
@ -2063,6 +2119,7 @@ set_into_collide_mask(CollideMask mask) {
if (any_changed) {
mark_bounds_stale(current_thread);
mark_bam_modified();
}
}
@ -2281,6 +2338,7 @@ set_bounds_type(BoundingVolume::BoundsType bounds_type) {
// bounds that may need to be updated when the bounds_type
// changes.
mark_internal_bounds_stale(pipeline_stage, current_thread);
mark_bam_modified();
}
CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
}
@ -2322,6 +2380,7 @@ set_bounds(const BoundingVolume *volume) {
cdata->_user_bounds = volume->make_copy();
}
mark_bounds_stale(pipeline_stage, current_thread);
mark_bam_modified();
}
CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
}
@ -2573,6 +2632,7 @@ get_internal_bounds(int pipeline_stage, Thread *current_thread) const {
cdataw->_internal_bounds_computed = mark;
cdataw->_internal_bounds = internal_bounds;
cdataw->_internal_vertices = internal_vertices;
((PandaNode *)this)->mark_bam_modified();
return cdataw->_internal_bounds;
}
@ -2619,6 +2679,7 @@ get_internal_vertices(int pipeline_stage, Thread *current_thread) const {
cdataw->_internal_bounds_computed = mark;
cdataw->_internal_bounds = internal_bounds;
cdataw->_internal_vertices = internal_vertices;
((PandaNode *)this)->mark_bam_modified();
return cdataw->_internal_vertices;
}
@ -2647,6 +2708,7 @@ set_internal_bounds(const BoundingVolume *volume) {
}
CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
mark_bounds_stale(current_thread);
mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
@ -2680,6 +2742,7 @@ force_bounds_stale(int pipeline_stage, Thread *current_thread) {
{
CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
++cdata->_next_update;
mark_bam_modified();
// It is important that we allow this lock to be dropped before we
// continue up the graph; otherwise, we risk deadlock from another
@ -2924,6 +2987,7 @@ set_cull_callback() {
cdata->set_fancy_bit(FB_cull_callback, true);
}
CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
@ -2939,6 +3003,7 @@ disable_cull_callback() {
cdata->set_fancy_bit(FB_cull_callback, false);
}
CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
@ -3062,6 +3127,9 @@ stage_replace_child(PandaNode *orig_child, PandaNode *new_child,
force_bounds_stale(pipeline_stage, current_thread);
orig_child->parents_changed();
new_child->parents_changed();
mark_bam_modified();
orig_child->mark_bam_modified();
new_child->mark_bam_modified();
return true;
}
@ -3251,6 +3319,7 @@ detach_one_stage(NodePathComponent *child, int pipeline_stage,
parent_node->force_bounds_stale(pipeline_stage, current_thread);
parent_node->children_changed();
parent_node->mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
@ -3288,8 +3357,10 @@ reparent(NodePathComponent *new_parent, NodePathComponent *child, int sort,
if (new_parent != (NodePathComponent *)NULL) {
new_parent->get_node()->children_changed();
new_parent->get_node()->mark_bam_modified();
}
child->get_node()->parents_changed();
child->get_node()->mark_bam_modified();
return any_ok;
}
@ -4029,7 +4100,11 @@ update_bounds(int pipeline_stage, PandaNode::CDLockedStageReader &cdata) {
<< "} " << *this << "::update_bounds();\n";
}
nassertr(cdataw->_last_update == cdataw->_next_update, cdataw)
nassertr(cdataw->_last_update == cdataw->_next_update, cdataw);
// Even though implicit bounding volume is not (yet?) part of
// the bam stream.
mark_bam_modified();
return cdataw;
}
@ -4092,6 +4167,19 @@ write_datagram(BamWriter *manager, Datagram &dg) {
manager->write_cdata(dg, _cycler);
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::update_bam_nested
// Access: Public, Virtual
// Description: Called by the BamWriter when this object has not
// itself been modified recently, but it should check
// its nested objects for updates.
////////////////////////////////////////////////////////////////////
void PandaNode::
update_bam_nested(BamWriter *manager) {
CDReader cdata(_cycler);
cdata->update_bam_nested(manager);
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::write_recorder
// Access: Public
@ -4296,7 +4384,26 @@ write_datagram(BamWriter *manager, Datagram &dg) const {
write_up_list(*get_up(), manager, dg);
write_down_list(*get_down(), manager, dg);
write_down_list(*get_stashed(), manager, dg);
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::CData::update_bam_nested
// Access: Public
// Description: Called by the BamWriter when this object has not
// itself been modified recently, but it should check
// its nested objects for updates.
////////////////////////////////////////////////////////////////////
void PandaNode::CData::
update_bam_nested(BamWriter *manager) const {
// No need to check the state pointers for updates, since they're
// all immutable objects.
//manager->consider_update(_state);
//manager->consider_update(_transform);
//manager->consider_update(_effects);
update_up_list(*get_up(), manager);
update_down_list(*get_down(), manager);
update_down_list(*get_stashed(), manager);
}
////////////////////////////////////////////////////////////////////
@ -4344,9 +4451,9 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
//
// Get the parent and child pointers.
pi += complete_up_list(*modify_up(), p_list + pi, manager);
pi += complete_down_list(*modify_down(), p_list + pi, manager);
pi += complete_down_list(*modify_stashed(), p_list + pi, manager);
pi += complete_up_list(*modify_up(), "up", p_list + pi, manager);
pi += complete_down_list(*modify_down(), "down", p_list + pi, manager);
pi += complete_down_list(*modify_stashed(), "stashed", p_list + pi, manager);
// Since the _effects and _states members have been finalized by
// now, this should be safe.
@ -4417,10 +4524,9 @@ fillin(DatagramIterator &scan, BamReader *manager) {
}
//
fillin_up_list(*modify_up(), scan, manager);
fillin_down_list(*modify_down(), scan, manager);
fillin_down_list(*modify_stashed(), scan, manager);
fillin_up_list(*modify_up(), "up", scan, manager);
fillin_down_list(*modify_down(), "down", scan, manager);
fillin_down_list(*modify_stashed(), "stashed", scan, manager);
}
#ifdef HAVE_PYTHON
@ -4521,6 +4627,38 @@ write_down_list(const PandaNode::Down &down_list,
}
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::CData::update_up_list
// Access: Public
// Description: Calls consider_update on each node of the indicated
// up list.
////////////////////////////////////////////////////////////////////
void PandaNode::CData::
update_up_list(const PandaNode::Up &up_list, BamWriter *manager) const {
Up::const_iterator ui;
for (ui = up_list.begin(); ui != up_list.end(); ++ui) {
PandaNode *parent_node = (*ui).get_parent();
if (manager->has_object(parent_node)) {
manager->consider_update(parent_node);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::CData::update_down_list
// Access: Public
// Description: Calls consider_update on each node of the indicated
// up list.
////////////////////////////////////////////////////////////////////
void PandaNode::CData::
update_down_list(const PandaNode::Down &down_list, BamWriter *manager) const {
Down::const_iterator di;
for (di = down_list.begin(); di != down_list.end(); ++di) {
PandaNode *child_node = (*di).get_child();
manager->consider_update(child_node);
}
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::CData::complete_up_list
// Access: Public
@ -4528,27 +4666,27 @@ write_down_list(const PandaNode::Down &down_list,
// pointers.
////////////////////////////////////////////////////////////////////
int PandaNode::CData::
complete_up_list(PandaNode::Up &up_list,
complete_up_list(PandaNode::Up &up_list, const string &tag,
TypedWritable **p_list, BamReader *manager) {
int pi = 0;
// Get the parent pointers.
Up::iterator ui;
for (ui = up_list.begin(); ui != up_list.end(); ++ui) {
int num_parents = manager->get_int_tag(tag);
Up new_up_list(PandaNode::get_class_type());
new_up_list.reserve(num_parents);
for (int i = 0; i < num_parents; i++) {
PandaNode *parent_node = DCAST(PandaNode, p_list[pi++]);
// For some reason, VC++ won't accept UpConnection as an inline
// temporary constructor here ("C2226: unexpected type
// PandaNode::UpConnection"), so we must make this assignment
// using an explicit temporary variable.
UpConnection connection(parent_node);
(*ui) = connection;
new_up_list.push_back(connection);
}
// Now we should sort the list, since the sorting is based on
// pointer order, which might be different from one session to the
// next.
up_list.sort();
new_up_list.sort();
// Make it permanent.
up_list.swap(new_up_list);
new_up_list.clear();
return pi;
}
@ -4560,21 +4698,29 @@ complete_up_list(PandaNode::Up &up_list,
// pointers.
////////////////////////////////////////////////////////////////////
int PandaNode::CData::
complete_down_list(PandaNode::Down &down_list,
complete_down_list(PandaNode::Down &down_list, const string &tag,
TypedWritable **p_list, BamReader *manager) {
int pi = 0;
Down::iterator di;
for (di = down_list.begin(); di != down_list.end(); ++di) {
int sort = (*di).get_sort();
PT(PandaNode) child_node = DCAST(PandaNode, p_list[pi++]);
(*di) = DownConnection(child_node, sort);
BamReaderAuxDataDown *aux;
DCAST_INTO_R(aux, manager->get_aux_tag(tag), pi);
Down &new_down_list = aux->_down_list;
for (Down::iterator di = new_down_list.begin();
di != new_down_list.end();
++di) {
PandaNode *child_node = DCAST(PandaNode, p_list[pi++]);
(*di).set_child(child_node);
}
// Unlike the up list, we should *not* sort the down list. The down
// list is stored in a specific order, not related to pointer order;
// and this order should be preserved from one session to the next.
// Make it permanent.
down_list.swap(new_down_list);
new_down_list.clear();
return pi;
}
@ -4586,15 +4732,11 @@ complete_down_list(PandaNode::Down &down_list,
// each one).
////////////////////////////////////////////////////////////////////
void PandaNode::CData::
fillin_up_list(PandaNode::Up &up_list,
fillin_up_list(PandaNode::Up &up_list, const string &tag,
DatagramIterator &scan, BamReader *manager) {
int num_parents = scan.get_uint16();
// Read the list of parent nodes. Push back a NULL for each one.
up_list.reserve(num_parents);
for (int i = 0; i < num_parents; i++) {
manager->read_pointer(scan);
up_list.push_back(UpConnection(NULL));
}
manager->set_int_tag(tag, num_parents);
manager->read_pointers(scan, num_parents);
}
////////////////////////////////////////////////////////////////////
@ -4605,16 +4747,28 @@ fillin_up_list(PandaNode::Up &up_list,
// each one).
////////////////////////////////////////////////////////////////////
void PandaNode::CData::
fillin_down_list(PandaNode::Down &down_list,
fillin_down_list(PandaNode::Down &down_list, const string &tag,
DatagramIterator &scan, BamReader *manager) {
int num_children = scan.get_uint16();
// Read the list of child nodes. Push back a NULL for each one.
down_list.reserve(num_children);
// Create a temporary down_list, with the right number of elements,
// but a NULL value for each pointer (we'll fill in the pointers
// later). We need to do this to associate the sort values with
// their pointers.
Down new_down_list(PandaNode::get_class_type());
new_down_list.reserve(num_children);
for (int i = 0; i < num_children; i++) {
manager->read_pointer(scan);
int sort = scan.get_int32();
down_list.push_back(DownConnection(NULL, sort));
DownConnection connection(NULL, sort);
new_down_list.push_back(connection);
}
// Now store the temporary down_list in the BamReader, so we can get
// it during the call to complete_down_list().
PT(BamReaderAuxDataDown) aux = new BamReaderAuxDataDown;
aux->_down_list.swap(new_down_list);
manager->set_aux_tag(tag, aux);
}
////////////////////////////////////////////////////////////////////

View File

@ -83,6 +83,7 @@ private:
void operator = (const PandaNode &copy);
public:
virtual ReferenceCount *as_reference_count();
virtual PandaNode *make_copy() const;
virtual PandaNode *dupe_for_flatten() const;
@ -428,7 +429,33 @@ public:
};
private:
typedef CopyOnWriteObj1< ov_multiset<DownConnection>, TypeHandle > Down;
typedef ov_multiset<DownConnection> DownList;
typedef CopyOnWriteObj1< DownList, TypeHandle > Down;
// Store a pointer to the down_list during the bam read pass.
class BamReaderAuxDataDown : public BamReaderAuxData {
public:
INLINE BamReaderAuxDataDown();
Down _down_list;
public:
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
static TypeHandle get_class_type() {
return _type_handle;
}
public:
static void init_type() {
BamReaderAuxData::init_type();
register_type(_type_handle, "BamReaderAuxDataDown",
BamReaderAuxData::get_class_type());
}
private:
static TypeHandle _type_handle;
};
class EXPCL_PANDA_PGRAPH UpConnection {
public:
@ -441,7 +468,8 @@ private:
// children do not circularly reference each other.
PandaNode *_parent;
};
typedef CopyOnWriteObj1< ov_set<UpConnection>, TypeHandle > Up;
typedef ov_set<UpConnection> UpList;
typedef CopyOnWriteObj1< UpList, TypeHandle > Up;
// We also maintain a set of NodePathComponents in the node. This
// represents the set of instances of this node that we have
@ -480,7 +508,8 @@ private:
ALLOC_DELETED_CHAIN(CData);
virtual CycleData *make_copy() const;
virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
void update_bam_nested(BamWriter *manager) const;
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
virtual void fillin(DatagramIterator &scan, BamReader *manager);
virtual TypeHandle get_parent_type() const {
@ -579,13 +608,15 @@ private:
BamWriter *manager, Datagram &dg) const;
void write_down_list(const Down &down_list,
BamWriter *manager, Datagram &dg) const;
int complete_up_list(Up &up_list,
void update_up_list(const Up &up_list, BamWriter *manager) const;
void update_down_list(const Down &down_list, BamWriter *manager) const;
int complete_up_list(Up &up_list, const string &tag,
TypedWritable **p_list, BamReader *manager);
int complete_down_list(Down &down_list,
int complete_down_list(Down &down_list, const string &tag,
TypedWritable **p_list, BamReader *manager);
void fillin_up_list(Up &up_list,
void fillin_up_list(Up &up_list, const string &tag,
DatagramIterator &scan, BamReader *manager);
void fillin_down_list(Down &down_list,
void fillin_down_list(Down &down_list, const string &tag,
DatagramIterator &scan, BamReader *manager);
INLINE CPT(Down) get_down() const;
@ -696,6 +727,7 @@ private:
public:
static void register_with_read_factory();
virtual void write_datagram(BamWriter *manager, Datagram &dg);
virtual void update_bam_nested(BamWriter *manager);
void write_recorder(BamWriter *manager, Datagram &dg);
protected:
@ -716,6 +748,7 @@ public:
CData::init_type();
Down::init_type();
Up::init_type();
BamReaderAuxDataDown::init_type();
}
virtual TypeHandle get_type() const {
return get_class_type();

View File

@ -137,7 +137,7 @@ cull_callback(CullTraverser *, const CullTraverserData &) const {
////////////////////////////////////////////////////////////////////
// Function: RenderAttrib::unref
// Access: Published
// Access: Published, Virtual
// Description: This method overrides ReferenceCount::unref() to
// clear the pointer from the global object pool when
// its reference count goes to zero.

View File

@ -78,7 +78,7 @@ PUBLISHED:
INLINE int compare_to(const RenderAttrib &other) const;
INLINE CPT(RenderAttrib) get_unique() const;
bool unref() const;
virtual bool unref() const;
virtual void output(ostream &out) const;
virtual void write(ostream &out, int indent_level) const;

View File

@ -382,7 +382,7 @@ get_effect(TypeHandle type) const {
////////////////////////////////////////////////////////////////////
// Function: RenderEffects::unref
// Access: Published
// Access: Published, Virtual
// Description: This method overrides ReferenceCount::unref() to
// check whether the remaining reference count is
// entirely in the cache, and if so, it checks for and

View File

@ -85,7 +85,7 @@ PUBLISHED:
const RenderEffect *get_effect(TypeHandle type) const;
bool unref() const;
virtual bool unref() const;
void output(ostream &out) const;
void write(ostream &out, int indent_level) const;

View File

@ -696,20 +696,13 @@ adjust_all_priorities(int adjustment) const {
////////////////////////////////////////////////////////////////////
// Function: RenderState::unref
// Access: Published
// Access: Published, Virtual
// Description: This method overrides ReferenceCount::unref() to
// check whether the remaining reference count is
// entirely in the cache, and if so, it checks for and
// breaks a cycle in the cache involving this object.
// This is designed to prevent leaks from cyclical
// references within the cache.
//
// Note that this is not a virtual method, and cannot be
// because ReferenceCount itself declares no virtual
// methods (it avoids the overhead of a virtual function
// pointer). But this doesn't matter, because
// PT(TransformState) is a template class, and will call
// the appropriate method even though it is non-virtual.
////////////////////////////////////////////////////////////////////
bool RenderState::
unref() const {

View File

@ -110,7 +110,7 @@ PUBLISHED:
INLINE CPT(RenderState) get_unique() const;
bool unref() const;
virtual bool unref() const;
INLINE void cache_ref() const;
INLINE bool cache_unref() const;

View File

@ -771,20 +771,13 @@ invert_compose(const TransformState *other) const {
////////////////////////////////////////////////////////////////////
// Function: TransformState::unref
// Access: Published
// Access: Published, Virtual
// Description: This method overrides ReferenceCount::unref() to
// check whether the remaining reference count is
// entirely in the cache, and if so, it checks for and
// breaks a cycle in the cache involving this object.
// This is designed to prevent leaks from cyclical
// references within the cache.
//
// Note that this is not a virtual method, and cannot be
// because ReferenceCount itself declares no virtual
// methods (it avoids the overhead of a virtual function
// pointer). But this doesn't matter, because
// PT(TransformState) is a template class, and will call
// the appropriate method even though it is non-virtual.
////////////////////////////////////////////////////////////////////
bool TransformState::
unref() const {
@ -2421,47 +2414,17 @@ write_datagram(BamWriter *manager, Datagram &dg) {
// Once this function has been called, the old pointer
// will no longer be accessed.
////////////////////////////////////////////////////////////////////
TypedWritable *TransformState::
change_this(TypedWritable *old_ptr, BamReader *manager) {
PT(TypedWritableReferenceCount) TransformState::
change_this(TypedWritableReferenceCount *old_ptr, BamReader *manager) {
// First, uniquify the pointer.
TransformState *state = DCAST(TransformState, old_ptr);
CPT(TransformState) pointer = return_unique(state);
// But now we have a problem, since we have to hold the reference
// count and there's no way to return a TypedWritable while still
// holding the reference count! We work around this by explicitly
// upping the count, and also setting a finalize() callback to down
// it later.
if (pointer == state) {
pointer->ref();
manager->register_finalize(state);
}
// We have to cast the pointer back to non-const, because the bam
// reader expects that.
return (TransformState *)pointer.p();
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::finalize
// Access: Public, Virtual
// Description: Called by the BamReader to perform any final actions
// needed for setting up the object after all objects
// have been read and all pointers have been completed.
////////////////////////////////////////////////////////////////////
void TransformState::
finalize(BamReader *) {
// Unref the pointer that we explicitly reffed in change_this().
unref();
// We should never get back to zero after unreffing our own count,
// because we expect to have been stored in a pointer somewhere. If
// we do get to zero, it's a memory leak; the way to avoid this is
// to call unref_delete() above instead of unref(), but this is
// dangerous to do from within a virtual function.
nassertv(get_ref_count() != 0);
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::make_from_bam
// Access: Protected, Static

View File

@ -173,7 +173,7 @@ PUBLISHED:
INLINE int get_geom_rendering(int geom_rendering) const;
bool unref() const;
virtual bool unref() const;
INLINE void cache_ref() const;
INLINE bool cache_unref() const;
@ -370,8 +370,7 @@ private:
public:
static void register_with_read_factory();
virtual void write_datagram(BamWriter *manager, Datagram &dg);
static TypedWritable *change_this(TypedWritable *old_ptr, BamReader *manager);
virtual void finalize(BamReader *manager);
static PT(TypedWritableReferenceCount) change_this(TypedWritableReferenceCount *old_ptr, BamReader *manager);
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);

View File

@ -14,10 +14,9 @@
bamCache.h bamCache.I \
bamCacheIndex.h bamCacheIndex.I \
bamCacheRecord.h bamCacheRecord.I \
bamEndian.h \
bamEnums.h \
bamReader.I bamReader.N bamReader.h bamReaderParam.I \
bamReaderParam.h \
bamTextureMode.h \
bamWriter.I bamWriter.h \
bitArray.I bitArray.h \
bitMask.I bitMask.h \
@ -78,9 +77,8 @@
bamCache.cxx \
bamCacheIndex.cxx \
bamCacheRecord.cxx \
bamEndian.cxx \
bamEnums.cxx \
bamReader.cxx bamReaderParam.cxx \
bamTextureMode.cxx \
bamWriter.cxx \
bitArray.cxx \
bitMask.cxx \
@ -128,9 +126,8 @@
bamCache.h bamCache.I \
bamCacheIndex.h bamCacheIndex.I \
bamCacheRecord.h bamCacheRecord.I \
bamEndian.h \
bamEnums.h \
bamReader.I bamReader.h bamReaderParam.I bamReaderParam.h \
bamTextureMode.h \
bamWriter.I bamWriter.h \
bitArray.I bitArray.h \
bitMask.I bitMask.h \

View File

@ -33,7 +33,7 @@ static const unsigned short _bam_major_ver = 6;
// Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData.
static const unsigned short _bam_first_minor_ver = 14;
static const unsigned short _bam_minor_ver = 20;
static const unsigned short _bam_minor_ver = 21;
// Bumped to minor version 14 on 12/19/07 to change default ColorAttrib.
// Bumped to minor version 15 on 4/9/08 to add TextureAttrib::_implicit_sort.
// Bumped to minor version 16 on 5/13/08 to add Texture::_quality_level.
@ -41,6 +41,7 @@ static const unsigned short _bam_minor_ver = 20;
// Bumped to minor version 18 on 8/14/08 to add Texture::_simple_ram_image.
// Bumped to minor version 19 on 8/14/08 to add PandaNode::_bounds_type.
// Bumped to minor version 20 on 4/21/09 to add MovingPartBase::_forced_channel.
// Bumped to minor version 21 on 2/26/08 to add BamEnums::BamObjectCode.
#endif

View File

@ -258,10 +258,10 @@ store(BamCacheRecord *record) {
TypeHandle texture_type = type_registry->find_type("Texture");
if (record->get_data()->is_of_type(texture_type)) {
// Texture objects write the actual texture image.
writer.set_file_texture_mode(BTM_rawdata);
writer.set_file_texture_mode(BamWriter::BTM_rawdata);
} else {
// Any other kinds of objects write texture references.
writer.set_file_texture_mode(BTM_fullpath);
writer.set_file_texture_mode(BamWriter::BTM_fullpath);
}
if (!writer.write_object(record)) {
@ -929,16 +929,17 @@ do_read_record(Filename &cache_pathname, bool read_data) {
if (read_data && record->dependents_unchanged()) {
// The cache record doesn't appear to be stale. Load the cached
// object.
object = reader.read_object();
TypedWritable *ptr;
ReferenceCount *ref_ptr;
if (object != (TypedWritable *)NULL) {
if (reader.read_object(ptr, ref_ptr)) {
if (!reader.resolve()) {
util_cat.debug()
<< "Unable to fully resolve cached object in " << cache_pathname << "\n";
delete object;
} else {
// The object is valid. Store it in the record.
record->set_data(object, true);
record->set_data(ptr, ref_ptr);
}
}
}

View File

@ -112,7 +112,7 @@ get_dependent_pathname(int n) const {
////////////////////////////////////////////////////////////////////
INLINE bool BamCacheRecord::
has_data() const {
return (_data != (TypedWritable *)NULL);
return (_ptr != (TypedWritable *)NULL);
}
////////////////////////////////////////////////////////////////////
@ -124,57 +124,85 @@ has_data() const {
////////////////////////////////////////////////////////////////////
INLINE void BamCacheRecord::
clear_data() {
if (_owns_pointer) {
delete _data;
if (_ref_ptr != NULL) {
unref_delete(_ref_ptr);
}
_data = NULL;
_owns_pointer = false;
_ptr = NULL;
_ref_ptr = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: BamCacheRecord::get_data
// Access: Published
// Description: Returns a read-only pointer to the data stored in the
// record, or NULL if there is no data. This does not
// change ownership of the data pointer.
// Description: Returns a pointer to the data stored in the
// record, or NULL if there is no data. The pointer is
// not removed from the record.
////////////////////////////////////////////////////////////////////
INLINE const TypedWritable *BamCacheRecord::
INLINE TypedWritable *BamCacheRecord::
get_data() const {
return _data;
return _ptr;
}
////////////////////////////////////////////////////////////////////
// Function: BamCacheRecord::extract_data
// Access: Published
// Description: Removes the in-memory data object associated with
// this record, and returns it. This transfers
// ownership of the data pointer; the caller will be
// responsible for subsequently deleting this object.
// Description: Fills ptr and ref_ptr with the two different-typed
// pointers to the same object, the data stored within
// this record. This transfers ownership of the data
// pointer; the caller will be responsible for managing
// the reference counts on this object subsequently.
//
// It is an error to call this if the record does not
// own the pointer.
// Returns true if the record contained any data (and
// the pointers have been filled), false if it didn't
// (and the pointers are NULL).
////////////////////////////////////////////////////////////////////
INLINE TypedWritable *BamCacheRecord::
extract_data() {
nassertr(_owns_pointer, NULL);
TypedWritable *result = _data;
_data = NULL;
_owns_pointer = false;
return result;
INLINE bool BamCacheRecord::
extract_data(TypedWritable *&ptr, ReferenceCount *&ref_ptr) {
ptr = _ptr;
ref_ptr = _ref_ptr;
clear_data();
return (ptr != (TypedWritable *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: BamCacheRecord::set_data
// Access: Published
// Description: Stores a new data object on the record. If
// owns_pointer is true, the record owns the pointer,
// and will eventually be responsible for deleting it.
// Description: Stores a new data object on the record. You should
// pass the same pointer twice, to both parameters; this
// allows the C++ typecasting to automatically convert
// the pointer into both a TypedWritable and a
// ReferenceCount pointer, so that the BamCacheRecord
// object can reliably manage the reference counts.
//
// You may pass 0 or NULL as the second parameter. If
// you do this, the BamCacheRecord will not manage the
// object's reference count; it will be up to you to
// ensure the object is not deleted during the lifetime
// of the BamCacheRecord object.
////////////////////////////////////////////////////////////////////
INLINE void BamCacheRecord::
set_data(TypedWritable *data, bool owns_pointer) {
clear_data();
_data = data;
_owns_pointer = owns_pointer;
set_data(TypedWritable *ptr, ReferenceCount *ref_ptr) {
if (_ptr != ptr) {
clear_data();
_ptr = ptr;
_ref_ptr = ref_ptr;
if (_ref_ptr != NULL) {
_ref_ptr->ref();
}
}
}
////////////////////////////////////////////////////////////////////
// Function: BamCacheRecord::set_data
// Access: Published
// Description: This variant on set_data() is provided just to allow
// Python code to pass a 0 as the second parameter.
////////////////////////////////////////////////////////////////////
INLINE void BamCacheRecord::
set_data(TypedWritable *ptr, int dummy) {
nassertv(dummy == 0);
set_data(ptr, (ReferenceCount *)NULL);
}
////////////////////////////////////////////////////////////////////

View File

@ -28,8 +28,8 @@ BamCacheRecord::
BamCacheRecord() :
_recorded_time(0),
_record_size(0),
_data(NULL),
_owns_pointer(false),
_ptr(NULL),
_ref_ptr(NULL),
_record_access_time(0)
{
}
@ -46,8 +46,8 @@ BamCacheRecord(const Filename &source_pathname,
_cache_filename(cache_filename),
_recorded_time(0),
_record_size(0),
_data(NULL),
_owns_pointer(false),
_ptr(NULL),
_ref_ptr(NULL),
_record_access_time(0)
{
}
@ -64,8 +64,8 @@ BamCacheRecord(const BamCacheRecord &copy) :
_cache_filename(copy._cache_filename),
_recorded_time(copy._recorded_time),
_record_size(copy._record_size),
_data(NULL),
_owns_pointer(false),
_ptr(NULL),
_ref_ptr(NULL),
_record_access_time(copy._record_access_time)
{
}

View File

@ -63,9 +63,10 @@ PUBLISHED:
INLINE bool has_data() const;
INLINE void clear_data();
INLINE const TypedWritable *get_data() const;
INLINE TypedWritable *extract_data();
INLINE void set_data(TypedWritable *data, bool owns_pointer);
INLINE TypedWritable *get_data() const;
INLINE bool extract_data(TypedWritable *&ptr, ReferenceCount *&ref_ptr);
INLINE void set_data(TypedWritable *ptr, ReferenceCount *ref_ptr);
INLINE void set_data(TypedWritable *ptr, int dummy);
void output(ostream &out) const;
void write(ostream &out, int indent_level = 0) const;
@ -97,8 +98,8 @@ private:
// The following are not recorded to disk; they are preserved
// in-memory only for the current session.
Filename _cache_pathname;
TypedWritable *_data;
bool _owns_pointer;
TypedWritable *_ptr;
ReferenceCount *_ref_ptr;
// The following are not recorded to disk, nor even returned by the
// BamCache interface. They are strictly meaningful to the

View File

@ -1,52 +0,0 @@
// Filename: bamEndian.cxx
// Created by: drose (07Jun05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "bamEndian.h"
#include "string_utils.h"
#include "config_util.h"
ostream &
operator << (ostream &out, BamEndian be) {
switch (be) {
case BE_bigendian:
return out << "bigendian";
case BE_littleendian:
return out << "littleendian";
}
return out << "**invalid BamEndian value: (" << (int)be << ")**";
}
istream &
operator >> (istream &in, BamEndian &be) {
string word;
in >> word;
if (cmp_nocase(word, "native") == 0) {
be = BE_native;
} else if (cmp_nocase(word, "bigendian") == 0) {
be = BE_bigendian;
} else if (cmp_nocase(word, "littleendian") == 0) {
be = BE_littleendian;
} else {
util_cat->error()
<< "Invalid bam_endian string: " << word << "\n";
be = BE_native;
}
return in;
}

View File

@ -1,38 +0,0 @@
// Filename: bamEndian.h
// Created by: drose (07Jun05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef BAMENDIAN_H
#define BAMENDIAN_H
#include "pandabase.h"
// This defines an enumerated type used to represent the endianness of
// certain numeric values stored in a Bam file. It really has only
// two possible values, either BE_bigendian or BE_littleendian; but
// through a preprocessor trick we also add BE_native, which is the
// same numerically as whichever value the hardware supports natively.
enum BamEndian {
BE_bigendian = 0,
BE_littleendian = 1,
#ifdef WORDS_BIGENDIAN
BE_native = 0,
#else
BE_native = 1,
#endif
};
EXPCL_PANDA_PUTIL ostream &operator << (ostream &out, BamEndian be);
EXPCL_PANDA_PUTIL istream &operator >> (istream &in, BamEndian &be);
#endif

View File

@ -0,0 +1,118 @@
// Filename: bamEnums.cxx
// Created by: drose (26Feb09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "bamEnums.h"
#include "string_utils.h"
#include "config_util.h"
ostream &
operator << (ostream &out, BamEnums::BamEndian be) {
switch (be) {
case BamEnums::BE_bigendian:
return out << "bigendian";
case BamEnums::BE_littleendian:
return out << "littleendian";
}
return out << "**invalid BamEnums::BamEndian value: (" << (int)be << ")**";
}
istream &
operator >> (istream &in, BamEnums::BamEndian &be) {
string word;
in >> word;
if (cmp_nocase(word, "native") == 0) {
be = BamEnums::BE_native;
} else if (cmp_nocase(word, "bigendian") == 0) {
be = BamEnums::BE_bigendian;
} else if (cmp_nocase(word, "littleendian") == 0) {
be = BamEnums::BE_littleendian;
} else {
util_cat->error()
<< "Invalid bam_endian string: " << word << "\n";
be = BamEnums::BE_native;
}
return in;
}
ostream &
operator << (ostream &out, BamEnums::BamObjectCode boc) {
switch (boc) {
case BamEnums::BOC_push:
return out << "push";
case BamEnums::BOC_pop:
return out << "pop";
case BamEnums::BOC_adjunct:
return out << "adjunct";
case BamEnums::BOC_remove:
return out << "remove";
}
return out << "**invalid BamEnums::BamObjectCode value: (" << (int)boc << ")**";
}
ostream &
operator << (ostream &out, BamEnums::BamTextureMode btm) {
switch (btm) {
case BamEnums::BTM_unchanged:
return out << "unchanged";
case BamEnums::BTM_fullpath:
return out << "fullpath";
case BamEnums::BTM_relative:
return out << "relative";
case BamEnums::BTM_basename:
return out << "basename";
case BamEnums::BTM_rawdata:
return out << "rawdata";
}
return out << "**invalid BamEnums::BamTextureMode (" << (int)btm << ")**";
}
istream &
operator >> (istream &in, BamEnums::BamTextureMode &btm) {
string word;
in >> word;
if (cmp_nocase(word, "unchanged") == 0) {
btm = BamEnums::BTM_unchanged;
} else if (cmp_nocase(word, "fullpath") == 0) {
btm = BamEnums::BTM_fullpath;
} else if (cmp_nocase(word, "relative") == 0) {
btm = BamEnums::BTM_relative;
} else if (cmp_nocase(word, "basename") == 0) {
btm = BamEnums::BTM_basename;
} else if (cmp_nocase(word, "rawdata") == 0) {
btm = BamEnums::BTM_rawdata;
} else {
util_cat->error() << "Invalid BamEnums::BamTextureMode value: " << word << "\n";
btm = BamEnums::BTM_relative;
}
return in;
}

View File

@ -0,0 +1,77 @@
// Filename: bamEnums.h
// Created by: drose (26Feb09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef BAMENUMS_H
#define BAMENUMS_H
#include "pandabase.h"
////////////////////////////////////////////////////////////////////
// Class : BamEnums
// Description : This class exists just to provide scoping for the
// enums shared by BamReader and BamWriter.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_PUTIL BamEnums {
PUBLISHED:
// This defines an enumerated type used to represent the endianness of
// certain numeric values stored in a Bam file. It really has only
// two possible values, either BE_bigendian or BE_littleendian; but
// through a preprocessor trick we also add BE_native, which is the
// same numerically as whichever value the hardware supports natively.
enum BamEndian {
BE_bigendian = 0,
BE_littleendian = 1,
#ifdef WORDS_BIGENDIAN
BE_native = 0,
#else
BE_native = 1,
#endif
};
// This is the code written along with each object. It is used to
// control object scoping. A BOC_push includes an object
// definition, and will always be eventually paired with a BOC_pop
// (which does not). A BOC_adjunct includes an object definition
// but does not push the level; it is associated with the current
// level. BOC_remove lists object ID's that have been deallocated
// on the sender end.
enum BamObjectCode {
BOC_push,
BOC_pop,
BOC_adjunct,
BOC_remove,
};
// This enum is used to control how textures are written to a bam
// stream.
enum BamTextureMode {
BTM_unchanged,
BTM_fullpath,
BTM_relative,
BTM_basename,
BTM_rawdata
};
};
EXPCL_PANDA_PUTIL ostream &operator << (ostream &out, BamEnums::BamEndian be);
EXPCL_PANDA_PUTIL istream &operator >> (istream &in, BamEnums::BamEndian &be);
EXPCL_PANDA_PUTIL ostream &operator << (ostream &out, BamEnums::BamObjectCode boc);
EXPCL_PANDA_PUTIL ostream &operator << (ostream &out, BamEnums::BamTextureMode btm);
EXPCL_PANDA_PUTIL istream &operator >> (istream &in, BamEnums::BamTextureMode &btm);
#endif

View File

@ -13,6 +13,15 @@
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: BamReaderAuxData::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE BamReaderAuxData::
BamReaderAuxData() {
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::get_filename
// Access: Public
@ -90,7 +99,7 @@ get_file_minor_ver() const {
// convention, but individual objects may choose to
// respect this flag when recording data.
////////////////////////////////////////////////////////////////////
INLINE BamEndian BamReader::
INLINE BamReader::BamEndian BamReader::
get_file_endian() const {
return _file_endian;
}
@ -199,6 +208,65 @@ INLINE BamReader::AuxData::
AuxData() {
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::CreatedObj::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE BamReader::CreatedObj::
CreatedObj() :
_created(false),
_ptr(NULL),
_ref_ptr(NULL),
_change_this(NULL),
_change_this_ref(NULL)
{
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::CreatedObj::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE BamReader::CreatedObj::
~CreatedObj() {
set_ptr(NULL, NULL);
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::CreatedObj::set_ptr
// Access: Public
// Description: Replaces the pointer to the created object. There
// are actually two pointers to the same object in
// different forms: a generic TypedWritable pointer, and
// an untyped ReferenceCount pointer. We need both
// pointers because some objects (like PandaNode)
// inherit from TypedWritable and ReferenceCount
// independently.
//
// Managing a typed pointer and an untyped
// ReferenceCount pointer to the same object takes just
// a bit of extra care.
////////////////////////////////////////////////////////////////////
INLINE void BamReader::CreatedObj::
set_ptr(TypedWritable *ptr, ReferenceCount *ref_ptr) {
if (_ptr != ptr) {
if (_ref_ptr != NULL) {
nassertv(_ref_ptr != ref_ptr);
unref_delete(_ref_ptr);
}
_ptr = ptr;
_ref_ptr = ref_ptr;
if (_ref_ptr != NULL) {
_ref_ptr->ref();
}
} else {
nassertv(_ref_ptr == ref_ptr);
}
}
////////////////////////////////////////////////////////////////////
// Function: parse_params
// Access: Private, Static
@ -216,3 +284,4 @@ parse_params(const FactoryParams &params,
scan = param->get_iterator();
manager = param->get_manager();
}

View File

@ -21,7 +21,7 @@
#include "config_util.h"
#include "pipelineCyclerBase.h"
TypeHandle BamReader::_remove_flag;
TypeHandle BamReaderAuxData::_type_handle;
WritableFactory *BamReader::_factory = (WritableFactory*)0L;
BamReader *const BamReader::Null = (BamReader*)0L;
@ -43,6 +43,7 @@ BamReader(DatagramGenerator *generator, const Filename &name)
: _source(generator), _filename(name)
{
_num_extra_objects = 0;
_nesting_level = 0;
_now_creating = _created_objs.end();
_reading_cycler = (PipelineCyclerBase *)NULL;
_pta_id = -1;
@ -58,6 +59,8 @@ BamReader(DatagramGenerator *generator, const Filename &name)
////////////////////////////////////////////////////////////////////
BamReader::
~BamReader() {
nassertv(_num_extra_objects == 0);
nassertv(_nesting_level == 0);
}
////////////////////////////////////////////////////////////////////
@ -195,6 +198,7 @@ get_aux_data(TypedWritable *obj, const string &name) const {
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::read_object
// Access: Public
@ -218,10 +222,42 @@ get_aux_data(TypedWritable *obj, const string &name) const {
// 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().
//
// This flavor of read_object() requires the caller to
// know what type of object it has received in order to
// properly manage the reference counts.
////////////////////////////////////////////////////////////////////
TypedWritable *BamReader::
read_object() {
nassertr(_num_extra_objects == 0, (TypedWritable *)NULL);
TypedWritable *ptr;
ReferenceCount *ref_ptr;
if (!read_object(ptr, ref_ptr)) {
return NULL;
}
return ptr;
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::read_object
// Access: Public
// Description: Reads a single object from the Bam file.
//
// This flavor of read_object() returns both a
// TypedWritable and a ReferenceCount pointer to the
// same object, so the reference count may be tracked
// reliably, without having to know precisely what type
// of object we have. It returns true on success, or
// false on failure.
////////////////////////////////////////////////////////////////////
bool BamReader::
read_object(TypedWritable *&ptr, ReferenceCount *&ref_ptr) {
ptr = NULL;
ref_ptr = NULL;
nassertr(_num_extra_objects == 0, false);
int start_level = _nesting_level;
// First, read the base object.
int object_id = p_read_object();
@ -230,19 +266,28 @@ read_object() {
// objects, which may still need to be read. And those objects
// might in turn require reading additional objects. Read all the
// remaining objects.
// Prior to 6.21, we kept track of _num_extra_objects to know when
// we're done.
while (_num_extra_objects > 0) {
p_read_object();
_num_extra_objects--;
}
// Beginning with 6.21, we use explicit nesting commands to know
// when we're done.
while (_nesting_level > start_level) {
p_read_object();
}
// Now look up the pointer of the object we read first. It should
// be available now.
if (object_id == 0) {
if (bam_cat.is_spam()) {
bam_cat.spam()
<< "Returning NULL\n";
<< "Returning false\n";
}
return (TypedWritable *)NULL;
return false;
}
CreatedObjs::iterator oi = _created_objs.find(object_id);
@ -250,25 +295,27 @@ read_object() {
if (oi == _created_objs.end()) {
bam_cat.error()
<< "Undefined object encountered!\n";
return (TypedWritable *)NULL;
return false;
} else {
CreatedObj &created_obj = (*oi).second;
TypedWritable *object = created_obj._ptr;
ptr = created_obj._ptr;
ref_ptr = created_obj._ref_ptr;
if (bam_cat.is_spam()) {
if (object != (TypedWritable *)NULL) {
if (ptr != (TypedWritable *)NULL) {
bam_cat.spam()
<< "Returning object of type " << object->get_type() << "\n";
<< "Returning object of type " << ptr->get_type() << "\n";
}
}
if (created_obj._change_this != NULL) {
if (created_obj._change_this != NULL ||
created_obj._change_this_ref != NULL) {
bam_cat.warning()
<< "Returning pointer to " << object->get_type()
<< "Returning pointer to " << ptr->get_type()
<< " that might change.\n";
}
return object;
return true;
}
}
@ -296,6 +343,10 @@ resolve() {
bool any_completed_this_pass;
do {
if (bam_cat.is_spam()) {
bam_cat.spam()
<< "resolve pass begin\n";
}
all_completed = true;
any_completed_this_pass = false;
@ -312,6 +363,11 @@ resolve() {
TypedWritable *object_ptr = created_obj._ptr;
// Update _now_creating, so a call to get_int_tag() from within
// complete_pointers() will come to the right place.
CreatedObjs::iterator was_creating = _now_creating;
_now_creating = ci;
if (resolve_object_pointers(object_ptr, pref)) {
// Now remove this object from the list of things that need
// completion. We have to be a bit careful when deleting things
@ -319,9 +375,35 @@ resolve() {
ObjectPointers::iterator old = oi;
++oi;
_object_pointers.erase(old);
any_completed_this_pass = true;
// Does the pointer need to change?
if (created_obj._change_this != NULL) {
if (created_obj._change_this_ref != NULL) {
// Reference-counting variant.
TypedWritableReferenceCount *object_ref_ptr = (TypedWritableReferenceCount *)object_ptr;
nassertr(created_obj._ref_ptr == NULL || created_obj._ref_ptr == object_ref_ptr, false);
PT(TypedWritableReferenceCount) new_ptr = created_obj._change_this_ref(object_ref_ptr, this);
if (new_ptr != object_ref_ptr) {
// Also update the reverse
vector_int &old_refs = _created_objs_by_pointer[object_ptr];
vector_int &new_refs = _created_objs_by_pointer[new_ptr];
for (vector_int::const_iterator oi = old_refs.begin();
oi != old_refs.end();
++oi) {
new_refs.push_back(*oi);
}
_created_objs_by_pointer.erase(object_ptr);
// Remove the pointer from the finalize list (the new
// pointer presumably doesn't require finalizing).
_finalize_list.erase(object_ptr);
}
created_obj.set_ptr(new_ptr, new_ptr);
created_obj._change_this = NULL;
created_obj._change_this_ref = NULL;
} else if (created_obj._change_this != NULL) {
// Non-reference-counting variant.
TypedWritable *new_ptr = created_obj._change_this(object_ptr, this);
if (new_ptr != object_ptr) {
// Also update the reverse
@ -338,18 +420,26 @@ resolve() {
// pointer presumably doesn't require finalizing).
_finalize_list.erase(object_ptr);
}
created_obj._ptr = new_ptr;
created_obj.set_ptr(new_ptr, new_ptr->as_reference_count());
created_obj._change_this = NULL;
created_obj._change_this_ref = NULL;
}
any_completed_this_pass = true;
} else {
// Couldn't complete this object yet; it'll wait for next time.
++oi;
all_completed = false;
}
_now_creating = was_creating;
}
if (bam_cat.is_spam()) {
bam_cat.spam()
<< "resolve pass end: all_completed = " << all_completed
<< " any_completed_this_pass = " << any_completed_this_pass
<< "\n";
}
} while (!all_completed && any_completed_this_pass);
if (all_completed) {
@ -420,7 +510,8 @@ change_pointer(const TypedWritable *orig_pointer, const TypedWritable *new_point
nassertr(ci != _created_objs.end(), false);
nassertr((*ci).second._ptr == orig_pointer, false);
(*ci).second._ptr = (TypedWritable *)new_pointer;
TypedWritable *ptr = (TypedWritable *)new_pointer;
(*ci).second.set_ptr(ptr, ptr->as_reference_count());
new_refs.push_back(object_id);
}
@ -539,7 +630,7 @@ read_handle(DatagramIterator &scan) {
// pointer to an object that appears later in the Bam
// file). Later, when all pointers are available, the
// complete_pointers() callback function will be called
// with an array of actual pointers, one for time
// with an array of actual pointers, one for each time
// read_pointer() was called. It is then the calling
// object's responsibilty to store these pointers in the
// object properly.
@ -566,10 +657,14 @@ read_pointer(DatagramIterator &scan) {
// 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.
/*
CreatedObj new_created_obj;
_created_objs.insert(CreatedObjs::value_type(object_id, new_created_obj)).second;
*/
if (get_file_minor_ver() < 21) {
// Prior to bam version 6.21, we expect to read an adjunct
// object for each non-NULL pointer we read.
_num_extra_objects++;
}
}
@ -624,8 +719,8 @@ read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler) {
////////////////////////////////////////////////////////////////////
// Function: BamReader::read_cdata
// Access: Public
// Description: This flavor of BamReader allows passing an additional
// parameter to cdata->fillin().
// Description: This flavor of read_cdata allows passing an
// additional parameter to cdata->fillin().
////////////////////////////////////////////////////////////////////
void BamReader::
read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler,
@ -638,6 +733,99 @@ read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler,
_reading_cycler = old_cycler;
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::set_int_tag
// Access: Public
// Description: Allows the creating object to store a temporary data
// value on the BamReader. This method may be called
// during an object's fillin() method; it will associate
// an integer value with an arbitrary string key (which
// is in turn associated with the calling object only).
// Later, in the complete_pointers() method, the same
// object may query this data again via get_int_tag().
//
// The tag string need not be unique between different
// objects, but it should be unique between an object
// and its CData object(s).
////////////////////////////////////////////////////////////////////
void BamReader::
set_int_tag(const string &tag, int value) {
nassertv(_now_creating != _created_objs.end());
int requestor_id = (*_now_creating).first;
PointerReference &pref = _object_pointers[requestor_id];
pref._int_tags[tag] = value;
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::get_int_tag
// Access: Public
// Description: Returns the value previously set via set_int_tag().
// It is an error if no value has been set.
////////////////////////////////////////////////////////////////////
int BamReader::
get_int_tag(const string &tag) const {
nassertr(_now_creating != _created_objs.end(), 0);
int requestor_id = (*_now_creating).first;
ObjectPointers::const_iterator opi = _object_pointers.find(requestor_id);
nassertr(opi != _object_pointers.end(), 0);
const PointerReference &pref = (*opi).second;
IntTags::const_iterator iti = pref._int_tags.find(tag);
nassertr(iti != pref._int_tags.end(), 0);
return (*iti).second;
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::set_aux_tag
// Access: Public
// Description: Allows the creating object to store a temporary data
// value on the BamReader. This method may be called
// during an object's fillin() method; it will associate
// a newly-allocated BamReaderAuxData construct with an
// arbitrary string key (which is in turn associated
// with the calling object only). Later, in the
// complete_pointers() method, the same object may query
// this data again via get_aux_tag().
//
// The BamReader will maintain the reference count on
// the BamReaderAuxData, and destruct it when it is
// cleaned up.
//
// The tag string need not be unique between different
// objects, but it should be unique between an object
// and its CData object(s).
////////////////////////////////////////////////////////////////////
void BamReader::
set_aux_tag(const string &tag, BamReaderAuxData *value) {
nassertv(_now_creating != _created_objs.end());
int requestor_id = (*_now_creating).first;
PointerReference &pref = _object_pointers[requestor_id];
pref._aux_tags[tag] = value;
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::get_aux_tag
// Access: Public
// Description: Returns the value previously set via set_aux_tag().
// It is an error if no value has been set.
////////////////////////////////////////////////////////////////////
BamReaderAuxData *BamReader::
get_aux_tag(const string &tag) const {
nassertr(_now_creating != _created_objs.end(), NULL);
int requestor_id = (*_now_creating).first;
ObjectPointers::const_iterator opi = _object_pointers.find(requestor_id);
nassertr(opi != _object_pointers.end(), NULL);
const PointerReference &pref = (*opi).second;
AuxTags::const_iterator ati = pref._aux_tags.find(tag);
nassertr(ati != pref._aux_tags.end(), NULL);
return (*ati).second;
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::register_finalize
// Access: Public
@ -691,7 +879,7 @@ register_change_this(ChangeThisFunc func, TypedWritable *object) {
// Sanity check the pointer--it should always be the same pointer
// after we set it the first time.
if (created_obj._ptr == (TypedWritable *)NULL) {
created_obj._ptr = object;
created_obj.set_ptr(object, object->as_reference_count());
} else {
// We've previously assigned this pointer, and we should have
// assigned it to the same this pointer we have now.
@ -700,6 +888,47 @@ register_change_this(ChangeThisFunc func, TypedWritable *object) {
#endif // NDEBUG
created_obj._change_this = func;
created_obj._change_this_ref = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::register_change_this
// Access: Public
// Description: Called by an object reading itself from the bam file
// to indicate that the object pointer that will be
// returned is temporary, and will eventually need to be
// replaced with another pointer.
//
// The supplied function pointer will later be called on
// the object, immediately after complete_pointers() is
// called; it should return the new and final pointer.
//
// We use a static function pointer instead of a virtual
// function (as in finalize()), to allow the function to
// destruct the old pointer if necessary. (It is
// invalid to destruct the this pointer within a virtual
// function.)
////////////////////////////////////////////////////////////////////
void BamReader::
register_change_this(ChangeThisRefFunc func, TypedWritableReferenceCount *object) {
nassertv(_now_creating != _created_objs.end());
CreatedObj &created_obj = (*_now_creating).second;
#ifndef NDEBUG
// Sanity check the pointer--it should always be the same pointer
// after we set it the first time.
if (created_obj._ptr == (TypedWritable *)NULL) {
created_obj.set_ptr(object, object);
} else {
// We've previously assigned this pointer, and we should have
// assigned it to the same this pointer we have now.
nassertv(created_obj._ptr == object);
nassertv(created_obj._ref_ptr == object);
}
#endif // NDEBUG
created_obj._change_this = NULL;
created_obj._change_this_ref = func;
}
////////////////////////////////////////////////////////////////////
@ -901,15 +1130,26 @@ p_read_object() {
// Now extract the object definition from the datagram.
DatagramIterator scan(packet);
// 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.
// First, read the BamObjectCode. In bam versions prior to 6.21,
// there was no BamObjectCode in the stream.
BamObjectCode boc = BOC_adjunct;
if (get_file_minor_ver() >= 21) {
boc = (BamObjectCode)scan.get_uint8();
}
switch (boc) {
case BOC_push:
++_nesting_level;
break;
TypeHandle type = read_handle(scan);
case BOC_pop:
--_nesting_level;
return 0;
if (type == _remove_flag) {
// The _remove_flag TypeHandle is a special case; it begins a
case BOC_adjunct:
break;
case BOC_remove:
// The BOC_remove code is a special case; it begins a
// record that simply lists all of the object ID's that are no
// longer important to the file and may be released.
free_object_ids(scan);
@ -920,6 +1160,13 @@ p_read_object() {
return p_read_object();
}
// 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.
TypeHandle type = read_handle(scan);
int object_id = read_object_id(scan);
// There are two cases (not counting the special _remove_flag case,
@ -940,94 +1187,127 @@ p_read_object() {
if (type != TypeHandle::none()) {
// Now we are going to read and create a new object.
// Define 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. For now, we give it a NULL pointer.
CreatedObj new_created_obj;
new_created_obj._ptr = NULL;
new_created_obj._change_this = NULL;
CreatedObjs::iterator oi =
_created_objs.insert(CreatedObjs::value_type(object_id, new_created_obj)).first;
CreatedObj &created_obj = (*oi).second;
// Now we can call the factory to create the object. Update
// _now_creating during this call so if this function calls
// read_pointer() or register_change_this() we'll match it up
// properly. This might recursively call back into this
// p_read_object(), so be sure to save and restore the original
// value of _now_creating.
CreatedObjs::iterator was_creating = _now_creating;
_now_creating = oi;
TypedWritable *object =
_factory->make_instance_more_general(type, fparams);
_now_creating = was_creating;
if (created_obj._ptr != NULL) {
// This object had already existed; thus, we are just receiving
// an update for it.
// And now we can store the new object pointer in the map.
nassertr(created_obj._ptr == object || created_obj._ptr == NULL, object_id);
created_obj._ptr = object;
if (created_obj._change_this != NULL) {
// If the pointer is scheduled to change after
// complete_pointers(), but we have no entry in
// _object_pointers for this object (and hence no plan to call
// complete_pointers()), then just change the pointer
// immediately.
ObjectPointers::const_iterator ri = _object_pointers.find(object_id);
if (ri == _object_pointers.end()) {
Finalize::iterator fi = _finalize_list.find((TypedWritable *)object);
TypedWritable *new_ptr = created_obj._change_this(object, this);
created_obj._ptr = new_ptr;
created_obj._change_this = NULL;
// Remove the pointer from the finalize list (the new
// pointer presumably doesn't require finalizing).
if (new_ptr != object) {
_finalize_list.erase(object);
}
object = new_ptr;
}
}
_created_objs_by_pointer[created_obj._ptr].push_back(object_id);
// Just some sanity checks
if (object == (TypedWritable *)NULL) {
if (bam_cat.is_debug()) {
bam_cat.debug()
<< "Unable to create an object of type " << type << endl;
}
} else if (object->get_type() != type) {
if (_new_types.find(type) != _new_types.end()) {
// This was a type we hadn't heard of before, so it's not
// really surprising we didn't know how to create it.
// Suppress the warning (make it a debug statement instead).
if (bam_cat.is_debug()) {
bam_cat.warning()
<< "Attempted to create a " << type.get_name() \
<< " but a " << object->get_type() \
<< " was created instead." << endl;
}
} else {
// This was a normal type that we should have known how to
// create. Report the error.
bam_cat.warning()
<< "Attempted to create a " << type.get_name() \
<< " but a " << object->get_type() \
<< " was created instead." << endl;
}
// Update _now_creating during this call so if this function
// calls read_pointer() or register_change_this() we'll match it
// up properly. This might recursively call back into this
// p_read_object(), so be sure to save and restore the original
// value of _now_creating.
CreatedObjs::iterator was_creating = _now_creating;
_now_creating = oi;
created_obj._ptr->fillin(scan, this);
_now_creating = was_creating;
} else {
if (bam_cat.is_spam()) {
bam_cat.spam()
<< "Read a " << object->get_type() << ": " << (void *)object << "\n";
// We are receiving a new object. Now we can call the factory
// to create the object.
// Define the parameters for passing to the object factory.
FactoryParams fparams;
fparams.add_param(new BamReaderParam(scan, this));
// As above, we update and preserve _now_creating during this
// call.
CreatedObjs::iterator was_creating = _now_creating;
_now_creating = oi;
TypedWritable *object =
_factory->make_instance_more_general(type, fparams);
_now_creating = was_creating;
// And now we can store the new object pointer in the map.
nassertr(created_obj._ptr == object || created_obj._ptr == NULL, object_id);
if (object == NULL) {
created_obj.set_ptr(NULL, NULL);
} else {
created_obj.set_ptr(object, object->as_reference_count());
}
created_obj._created = true;
if (created_obj._change_this_ref != NULL) {
// If the pointer is scheduled to change after
// complete_pointers(), but we have no entry in
// _object_pointers for this object (and hence no plan to call
// complete_pointers()), then just change the pointer
// immediately.
ObjectPointers::const_iterator ri = _object_pointers.find(object_id);
if (ri == _object_pointers.end()) {
PT(TypedWritableReferenceCount) object_ref = (*created_obj._change_this_ref)((TypedWritableReferenceCount *)object, this);
TypedWritable *new_ptr = object_ref;
created_obj.set_ptr(object_ref, object_ref);
created_obj._change_this = NULL;
created_obj._change_this_ref = NULL;
// Remove the pointer from the finalize list (the new
// pointer presumably doesn't require finalizing).
if (new_ptr != object) {
_finalize_list.erase(object);
}
object = new_ptr;
}
} else if (created_obj._change_this != NULL) {
// Non-reference-counting variant.
ObjectPointers::const_iterator ri = _object_pointers.find(object_id);
if (ri == _object_pointers.end()) {
TypedWritable *new_ptr = (*created_obj._change_this)(object, this);
created_obj.set_ptr(new_ptr, new_ptr->as_reference_count());
created_obj._change_this = NULL;
created_obj._change_this_ref = NULL;
if (new_ptr != object) {
_finalize_list.erase(object);
}
object = new_ptr;
}
}
_created_objs_by_pointer[created_obj._ptr].push_back(object_id);
// Just some sanity checks
if (object == (TypedWritable *)NULL) {
if (bam_cat.is_debug()) {
bam_cat.debug()
<< "Unable to create an object of type " << type << endl;
}
} else if (object->get_type() != type) {
if (_new_types.find(type) != _new_types.end()) {
// This was a type we hadn't heard of before, so it's not
// really surprising we didn't know how to create it.
// Suppress the warning (make it a debug statement instead).
if (bam_cat.is_debug()) {
bam_cat.warning()
<< "Attempted to create a " << type.get_name() \
<< " but a " << object->get_type() \
<< " was created instead." << endl;
}
} else {
// This was a normal type that we should have known how to
// create. Report the error.
bam_cat.warning()
<< "Attempted to create a " << type.get_name() \
<< " but a " << object->get_type() \
<< " was created instead." << endl;
}
} else {
if (bam_cat.is_spam()) {
bam_cat.spam()
<< "Read a " << object->get_type() << ": " << (void *)object << "\n";
}
}
}
}
@ -1074,6 +1354,11 @@ resolve_object_pointers(TypedWritable *object,
if (!pref._cycler_pointers.empty()) {
// If we didn't get all the cyclers, we have to wait.
if (bam_cat.is_spam()) {
bam_cat.spam()
<< "some cyclers pending: complete_pointers for " << (void *)object
<< " (" << object->get_type() << ")\n";
}
return false;
}
@ -1105,10 +1390,12 @@ resolve_object_pointers(TypedWritable *object,
} else {
const CreatedObj &child_obj = (*oi).second;
if (child_obj._change_this != NULL) {
if (!child_obj._created) {
// The child object hasn't yet been created.
is_complete = false;
} else if (child_obj._change_this != NULL || child_obj._change_this_ref != NULL) {
// It's been created, but the pointer might still change.
is_complete = false;
} else {
if (require_fully_complete &&
_object_pointers.find(child_id) != _object_pointers.end()) {
@ -1142,6 +1429,7 @@ resolve_object_pointers(TypedWritable *object,
bam_cat.warning()
<< object->get_type() << " completed " << num_completed
<< " of " << references.size() << " pointers.\n";
nassertr(num_completed < (int)references.size(), true);
}
return true;
@ -1194,7 +1482,7 @@ resolve_cycler_pointers(PipelineCyclerBase *cycler,
} else {
const CreatedObj &child_obj = (*oi).second;
if (child_obj._change_this != NULL) {
if (child_obj._change_this != NULL || child_obj._change_this_ref != NULL) {
// It's been created, but the pointer might still change.
is_complete = false;
@ -1227,6 +1515,7 @@ resolve_cycler_pointers(PipelineCyclerBase *cycler,
bam_cat.warning()
<< "CycleData object completed " << num_completed
<< " of " << references.size() << " pointers.\n";
nassertr(num_completed < (int)references.size(), true);
}
return true;
}

View File

@ -19,10 +19,12 @@
#include "pnotify.h"
#include "typedWritable.h"
#include "typedWritableReferenceCount.h"
#include "pointerTo.h"
#include "datagramGenerator.h"
#include "datagramIterator.h"
#include "bamReaderParam.h"
#include "bamEndian.h"
#include "bamEnums.h"
#include "loaderOptions.h"
#include "factory.h"
#include "vector_int.h"
@ -30,6 +32,7 @@
#include "pmap.h"
#include "dcast.h"
#include "pipelineCyclerBase.h"
#include "referenceCount.h"
#include <algorithm>
@ -49,6 +52,37 @@
} \
}
////////////////////////////////////////////////////////////////////
// Class : BamReaderAuxData
// Description : Stores auxiliary data that may be piggybacked on the
// BamReader during each object's read pass. To use
// this, subclass BamReaderAuxData and add whatever
// additional data you require.
////////////////////////////////////////////////////////////////////
class BamReaderAuxData : public TypedReferenceCount {
public:
INLINE BamReaderAuxData();
public:
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
static TypeHandle get_class_type() {
return _type_handle;
}
public:
static void init_type() {
TypedReferenceCount::init_type();
register_type(_type_handle, "BamReaderAuxData",
TypedReferenceCount::get_class_type());
}
private:
static TypeHandle _type_handle;
};
////////////////////////////////////////////////////////////////////
// Class : BamReader
// Description : This is the fundamental interface for extracting
@ -83,7 +117,7 @@
// See also BamFile, which defines a higher-level
// interface to read and write Bam files on disk.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_PUTIL BamReader {
class EXPCL_PANDA_PUTIL BamReader : public BamEnums {
public:
typedef Factory<TypedWritable> WritableFactory;
static BamReader *const Null;
@ -106,6 +140,8 @@ PUBLISHED:
INLINE void set_loader_options(const LoaderOptions &options);
TypedWritable *read_object();
bool read_object(TypedWritable *&ptr, ReferenceCount *&ref_ptr);
INLINE bool is_eof() const;
bool resolve();
@ -129,10 +165,18 @@ public:
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler,
void *extra_data);
void set_int_tag(const string &tag, int value);
int get_int_tag(const string &tag) const;
void set_aux_tag(const string &tag, BamReaderAuxData *value);
BamReaderAuxData *get_aux_tag(const string &tag) const;
void register_finalize(TypedWritable *whom);
typedef TypedWritable *(*ChangeThisFunc)(TypedWritable *object, BamReader *manager);
typedef PT(TypedWritableReferenceCount) (*ChangeThisRefFunc)(TypedWritableReferenceCount *object, BamReader *manager);
void register_change_this(ChangeThisFunc func, TypedWritable *whom);
void register_change_this(ChangeThisRefFunc func, TypedWritableReferenceCount *whom);
void finalize_now(TypedWritable *whom);
@ -164,10 +208,6 @@ private:
INLINE bool get_datagram(Datagram &datagram);
public:
// This special TypeHandle is written to the bam file to indicate an
// object id is no longer needed.
static TypeHandle _remove_flag;
// Inherit from this class to piggyback additional temporary data on
// the bamReader (via set_aux_data() and get_aux_data()) for any
// particular objects during the bam reading process.
@ -199,8 +239,16 @@ private:
// to the actual pointers of the corresponding generated objects.
class CreatedObj {
public:
INLINE CreatedObj();
INLINE ~CreatedObj();
INLINE void set_ptr(TypedWritable *ptr, ReferenceCount *ref_ptr);
public:
bool _created;
TypedWritable *_ptr;
ReferenceCount *_ref_ptr;
ChangeThisFunc _change_this;
ChangeThisRefFunc _change_this_ref;
};
typedef phash_map<int, CreatedObj, int_hash> CreatedObjs;
CreatedObjs _created_objs;
@ -222,19 +270,29 @@ private:
// in the order in which read_pointer() was called, so that we may
// call the appropriate complete_pointers() later.
typedef phash_map<PipelineCyclerBase *, vector_int, pointer_hash> CyclerPointers;
typedef pmap<string, int> IntTags;
typedef pmap<string, PT(BamReaderAuxData) > AuxTags;
class PointerReference {
public:
vector_int _objects;
CyclerPointers _cycler_pointers;
IntTags _int_tags;
AuxTags _aux_tags;
};
typedef phash_map<int, PointerReference, int_hash> ObjectPointers;
ObjectPointers _object_pointers;
// This is the number of extra objects that must still be read (and
// saved in the _created_objs map) before returning from
// read_object().
// read_object(). It is only used when read bam versions prior to
// 6.20.
int _num_extra_objects;
// The current nesting level. We are not done reading an object
// until we return to our starting nesting level. It is only used
// when reading bam versions of 6.20 or higher.
int _nesting_level;
// This is the set of all objects that registered themselves for
// finalization.
typedef phash_set<TypedWritable *, pointer_hash> Finalize;

View File

@ -1,63 +0,0 @@
// Filename: bamTextureMode.cxx
// Created by: drose (14Mar06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "bamTextureMode.h"
#include "config_util.h"
#include "string_utils.h"
ostream &
operator << (ostream &out, BamTextureMode btm) {
switch (btm) {
case BTM_unchanged:
return out << "unchanged";
case BTM_fullpath:
return out << "fullpath";
case BTM_relative:
return out << "relative";
case BTM_basename:
return out << "basename";
case BTM_rawdata:
return out << "rawdata";
}
return out << "**invalid BamTextureMode (" << (int)btm << ")**";
}
istream &
operator >> (istream &in, BamTextureMode &btm) {
string word;
in >> word;
if (cmp_nocase(word, "unchanged") == 0) {
btm = BTM_unchanged;
} else if (cmp_nocase(word, "fullpath") == 0) {
btm = BTM_fullpath;
} else if (cmp_nocase(word, "relative") == 0) {
btm = BTM_relative;
} else if (cmp_nocase(word, "basename") == 0) {
btm = BTM_basename;
} else if (cmp_nocase(word, "rawdata") == 0) {
btm = BTM_rawdata;
} else {
util_cat->error() << "Invalid BamTextureMode value: " << word << "\n";
btm = BTM_relative;
}
return in;
}

View File

@ -1,35 +0,0 @@
// Filename: bamTextureMode.h
// Created by: drose (14Mar06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef BAMTEXTUREMODE_H
#define BAMTEXTUREMODE_H
#include "pandabase.h"
BEGIN_PUBLISH
// This enum is used to control how textures are written to a bam
// stream.
enum BamTextureMode {
BTM_unchanged,
BTM_fullpath,
BTM_relative,
BTM_basename,
BTM_rawdata
};
END_PUBLISH
EXPCL_PANDA_PUTIL ostream &operator << (ostream &out, BamTextureMode btm);
EXPCL_PANDA_PUTIL istream &operator >> (istream &in, BamTextureMode &btm);
#endif

View File

@ -15,7 +15,7 @@
////////////////////////////////////////////////////////////////////
// Function: BamWriter::get_filename
// Access: Public
// Access: Published
// Description: If a BAM is a file, then the BamWriter should
// contain the name of the file. This enables the
// writer to convert pathnames in the BAM to relative
@ -28,34 +28,34 @@ get_filename() const {
////////////////////////////////////////////////////////////////////
// Function: BamWriter::get_file_endian
// Access: Public
// Access: Published
// Description: Returns the endian preference indicated by the Bam
// file currently being written. This does not imply
// that every number is stored using the indicated
// convention, but individual objects may choose to
// respect this flag when recording data.
////////////////////////////////////////////////////////////////////
INLINE BamEndian BamWriter::
INLINE BamWriter::BamEndian BamWriter::
get_file_endian() const {
return _file_endian;
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::get_file_texture_mode
// Access: Public
// Access: Published
// Description: Returns the BamTextureMode preference indicated by
// the Bam file currently being written. Texture
// objects written to this Bam file will be encoded
// according to the specified mode.
////////////////////////////////////////////////////////////////////
INLINE BamTextureMode BamWriter::
INLINE BamWriter::BamTextureMode BamWriter::
get_file_texture_mode() const {
return _file_texture_mode;
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::set_file_texture_mode
// Access: Public
// Access: Published
// Description: Changes the BamTextureMode preference for
// the Bam file currently being written. Texture
// objects written to this Bam file will be encoded

View File

@ -26,7 +26,7 @@
////////////////////////////////////////////////////////////////////
// Function: BamWriter::Constructor
// Access: Public
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
BamWriter::
@ -34,11 +34,13 @@ BamWriter(DatagramSink *sink, const Filename &name) :
_filename(name),
_target(sink)
{
++_writing_seq;
_next_boc = BOC_adjunct;
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::Destructor
// Access: Public
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
BamWriter::
@ -59,7 +61,7 @@ BamWriter::
////////////////////////////////////////////////////////////////////
// Function: BamWriter::init
// Access: Public
// Access: Published
// Description: Initializes the BamWriter prior to writing any
// objects to its output stream. This includes writing
// out the Bam header.
@ -96,7 +98,7 @@ init() {
////////////////////////////////////////////////////////////////////
// Function: BamWriter::write_object
// Access: Public
// Access: Published
// 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.
@ -118,15 +120,14 @@ init() {
////////////////////////////////////////////////////////////////////
bool BamWriter::
write_object(const TypedWritable *object) {
nassertr(_object_queue.empty(), false);
int object_id = enqueue_object(object);
nassertr(object_id != 0, false);
// Increment the _writing_seq, so we can check for newly stale
// objects during this operation.
++_writing_seq;
// If there are any freed objects to indicate, write them out now.
if (!_freed_object_ids.empty()) {
Datagram dg;
write_handle(dg, BamReader::_remove_flag);
dg.add_uint8(BOC_remove);
FreedObjectIds::iterator fi;
for (fi = _freed_object_ids.begin(); fi != _freed_object_ids.end(); ++fi) {
@ -141,74 +142,19 @@ write_object(const TypedWritable *object) {
}
}
// 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();
nassertr(_object_queue.empty(), false);
_next_boc = BOC_push;
// 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);
int object_id = (*si).second._object_id;
bool already_written = (*si).second._written;
int object_id = enqueue_object(object);
nassertr(object_id != 0, false);
if (!flush_queue()) {
return false;
}
// Finally, write the closing pop.
if (_next_boc != BOC_push) {
Datagram dg;
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);
// Determine what the nearest kind of type is that the reader
// will be able to handle, and write that instead.
TypeHandle registered_type =
BamReader::get_factory()->find_registered_type(type);
if (registered_type == TypeHandle::none()) {
// We won't be able to read this type again.
util_cat.warning()
<< "Objects of type " << type << " cannot be read; bam file is invalid.\n";
} else if (registered_type != type) {
util_cat.info()
<< "Writing " << registered_type << " instead of " << type << "\n";
type = registered_type;
} else if (util_cat.is_debug()) {
util_cat.debug()
<< "Writing " << type << " object id " << object_id
<< " to bam file\n";
}
write_handle(dg, type);
write_object_id(dg, object_id);
// We cast the const pointer to non-const so that we may call
// write_datagram() on it. Really, write_datagram() should be a
// const method anyway, but there may be times when a class
// object wants to update some transparent cache value during
// writing or something like that, so it's more convenient to
// cheat and define it as a non-const method.
((TypedWritable *)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());
write_object_id(dg, object_id);
}
dg.add_uint8(BOC_pop);
if (!_target->put_datagram(dg)) {
util_cat.error()
<< "Unable to write data to output.\n";
@ -221,7 +167,7 @@ write_object(const TypedWritable *object) {
////////////////////////////////////////////////////////////////////
// Function: BamWriter::has_object
// Access: Public
// Access: Published
// Description: Returns true if the object has previously been
// written (or at least requested to be written) to the
// bam file, or false if we've never heard of it before.
@ -232,6 +178,56 @@ has_object(const TypedWritable *object) const {
return (si != _state_map.end());
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::flush
// Access: Published
// Description: Ensures that all data written thus far is manifested
// on the output stream.
////////////////////////////////////////////////////////////////////
void BamWriter::
flush() {
_target->flush();
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::consider_update
// Access: Public
// Description: Should be called from
// TypedWritable::update_bam_nested() to recursively
// check the entire hiererachy of writable objects for
// needed updates. This tests the indicated
// TypedWritable object and writes it to the bam stream
// if it has recently been modified, then recurses
// through update_bam_nested.
////////////////////////////////////////////////////////////////////
void BamWriter::
consider_update(const TypedWritable *object) {
StateMap::iterator si = _state_map.find(object);
if (si == _state_map.end()) {
// This object has never even been seen before.
enqueue_object(object);
} else if ((*si).second._written_seq.is_initial()) {
// This object has not been written yet.
enqueue_object(object);
} else if ((*si).second._written_seq == _writing_seq) {
// We have already visited this object this pass, so no need to
// look closer.
} else if ((*si).second._modified != object->get_bam_modified()) {
// This object has been recently modified and needs to be rewritten.
enqueue_object(object);
} else {
// Mark that we have now visited this object and pronounced it clean.
(*si).second._written_seq = _writing_seq;
// Recurse to child objects.
((TypedWritable *)object)->update_bam_nested(this);
}
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::write_pointer
// Access: Public
@ -262,9 +258,27 @@ write_pointer(Datagram &packet, const TypedWritable *object) {
write_object_id(packet, object_id);
} else {
// We have already assigned this pointer an ID; thus, we can
// simply write out the ID.
write_object_id(packet, (*si).second._object_id);
// We have already assigned this pointer an ID, so it has
// previously been written; but we might still need to rewrite
// it if it is stale.
int object_id = (*si).second._object_id;
bool already_written = !(*si).second._written_seq.is_initial();
if ((*si).second._written_seq != _writing_seq &&
(*si).second._modified != object->get_bam_modified()) {
// This object was previously written, but it has since been
// modified, so we should write it again.
already_written = false;
}
write_object_id(packet, object_id);
if (!already_written) {
// It's stale, so queue the object for rewriting too.
enqueue_object(object);
} else {
// Not stale, but maybe its child object is.
((TypedWritable *)object)->update_bam_nested(this);
}
}
}
}
@ -407,6 +421,7 @@ write_handle(Datagram &packet, TypeHandle type) {
}
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::object_destructs
// Access: Private
@ -422,7 +437,7 @@ object_destructs(TypedWritable *object) {
if (si != _state_map.end()) {
// We ought to have written out the object by the time it
// destructs, or we're in trouble when we do write it out.
nassertv((*si).second._written);
nassertv(!(*si).second._written_seq.is_initial());
int object_id = (*si).second._object_id;
_freed_object_ids.push_back(object_id);
@ -529,3 +544,106 @@ enqueue_object(const TypedWritable *object) {
_object_queue.push_back(object);
return object_id;
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::flush_queue
// Access: Private
// Description: Writes all of the objects on the _object_queue to the
// bam stream, until the queue is empty.
//
// Returns true on success, false on failure.
////////////////////////////////////////////////////////////////////
bool BamWriter::
flush_queue() {
// Each object we write may append more to the queue.
while (!_object_queue.empty()) {
const TypedWritable *object = _object_queue.front();
_object_queue.pop_front();
// 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);
if ((*si).second._written_seq == _writing_seq) {
// We have already visited this object; no need to consider it again.
continue;
}
int object_id = (*si).second._object_id;
bool already_written = !(*si).second._written_seq.is_initial();
if ((*si).second._modified != object->get_bam_modified()) {
// This object was previously written, but it has since been
// modified, so we should write it again.
already_written = false;
}
Datagram dg;
dg.add_uint8(_next_boc);
_next_boc = BOC_adjunct;
if (!already_written) {
// The first time we write a particular object, or when we
// update the same object later, 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);
// Determine what the nearest kind of type is that the reader
// will be able to handle, and write that instead.
TypeHandle registered_type =
BamReader::get_factory()->find_registered_type(type);
if (registered_type == TypeHandle::none()) {
// We won't be able to read this type again.
util_cat.warning()
<< "Objects of type " << type << " cannot be read; bam file is invalid.\n";
} else if (registered_type != type) {
util_cat.info()
<< "Writing " << registered_type << " instead of " << type << "\n";
type = registered_type;
} else if (util_cat.is_debug()) {
util_cat.debug()
<< "Writing " << type << " object id " << object_id
<< " to bam file\n";
}
write_handle(dg, type);
write_object_id(dg, object_id);
// We cast the const pointer to non-const so that we may call
// write_datagram() on it. Really, write_datagram() should be a
// const method anyway, but there may be times when a class
// object wants to update some transparent cache value during
// writing or something like that, so it's more convenient to
// cheat and define it as a non-const method.
((TypedWritable *)object)->write_datagram(this, dg);
(*si).second._written_seq = _writing_seq;
(*si).second._modified = object->get_bam_modified();
} 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());
write_object_id(dg, object_id);
// The object has not been modified, but maybe one of its child
// objects has.
((TypedWritable *)object)->update_bam_nested(this);
}
if (!_target->put_datagram(dg)) {
util_cat.error()
<< "Unable to write data to output.\n";
return false;
}
}
return true;
}

View File

@ -17,8 +17,7 @@
#include "pandabase.h"
#include "pnotify.h"
#include "bamEndian.h"
#include "bamTextureMode.h"
#include "bamEnums.h"
#include "typedWritable.h"
#include "datagramSink.h"
#include "pdeque.h"
@ -71,7 +70,7 @@
// See also BamFile, which defines a higher-level
// interface to read and write Bam files on disk.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_PUTIL BamWriter {
class EXPCL_PANDA_PUTIL BamWriter : public BamEnums {
PUBLISHED:
BamWriter(DatagramSink *sink, const Filename &name = "");
~BamWriter();
@ -80,6 +79,7 @@ PUBLISHED:
INLINE const Filename &get_filename() const;
bool write_object(const TypedWritable *obj);
bool has_object(const TypedWritable *obj) const;
void flush();
INLINE BamEndian get_file_endian() const;
@ -89,6 +89,8 @@ PUBLISHED:
public:
// Functions to support classes that write themselves to the Bam.
void consider_update(const TypedWritable *obj);
void write_pointer(Datagram &packet, const TypedWritable *dest);
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler);
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler,
@ -102,6 +104,7 @@ private:
void write_object_id(Datagram &dg, int object_id);
void write_pta_id(Datagram &dg, int pta_id);
int enqueue_object(const TypedWritable *object);
bool flush_queue();
// This is the filename of the BAM, or null string if not in a file.
Filename _filename;
@ -118,13 +121,26 @@ private:
class StoreState {
public:
int _object_id;
bool _written;
UpdateSeq _written_seq;
UpdateSeq _modified;
StoreState(int object_id) : _object_id(object_id), _written(false) {}
StoreState(int object_id) : _object_id(object_id) {}
};
typedef phash_map<const TypedWritable *, StoreState, pointer_hash> StateMap;
StateMap _state_map;
// This seq number is incremented each time we write a new object
// using the top-level write_object() call. It indicates the
// current sequence number we are writing, which is updated in the
// StoreState, above, and used to keep track of which objects may
// need to be checked for internal updates.
UpdateSeq _writing_seq;
// This is initialized to BOC_push in write_object(), then cleared
// to BOC_adjunct as each object is written, so that only the first
// object gets written with BOC_push.
BamObjectCode _next_boc;
// This is the next object ID that will be assigned to a new object.
int _next_object_id;
bool _long_object_id;

View File

@ -174,7 +174,7 @@ cache_unref() const {
nassertr(_cache_ref_count > 0, 0);
AtomicAdjust::dec(((CachedTypedWritableReferenceCount *)this)->_cache_ref_count);
return unref();
return ReferenceCount::unref();
}
////////////////////////////////////////////////////////////////////

View File

@ -51,8 +51,8 @@ ConfigureDef(config_util);
NotifyCategoryDef(util, "");
NotifyCategoryDef(bam, util_cat);
ConfigVariableEnum<BamEndian> bam_endian
("bam-endian", BE_native,
ConfigVariableEnum<BamEnums::BamEndian> bam_endian
("bam-endian", BamEnums::BE_native,
PRC_DESC("The default endianness to use for writing major numeric data "
"tables to bam files. This does not affect all numbers written "
"to bam files, only those for which the individual object was "
@ -60,8 +60,8 @@ ConfigVariableEnum<BamEndian> bam_endian
"may set it to \"littleendian\" or \"bigendian\" to target a "
"particular platform."));
ConfigVariableEnum<BamTextureMode> bam_texture_mode
("bam-texture-mode", BTM_relative,
ConfigVariableEnum<BamEnums::BamTextureMode> bam_texture_mode
("bam-texture-mode", BamEnums::BTM_relative,
PRC_DESC("Set this to specify how textures should be written into Bam files."
"See the panda source or documentation for available options."));
@ -152,6 +152,7 @@ init_libputil() {
AnimInterface::init_type();
BamCacheIndex::init_type();
BamCacheRecord::init_type();
BamReaderAuxData::init_type();
BamReaderParam::init_type();
BitArray::init_type();
BitMask32::init_type();
@ -185,8 +186,6 @@ init_libputil() {
KeyboardButton::init_keyboard_buttons();
MouseButton::init_mouse_buttons();
register_type(BamReader::_remove_flag, "remove");
BamCacheIndex::register_with_read_factory();
BamCacheRecord::register_with_read_factory();

View File

@ -20,8 +20,7 @@
#include "configVariableSearchPath.h"
#include "configVariableEnum.h"
#include "configVariableDouble.h"
#include "bamEndian.h"
#include "bamTextureMode.h"
#include "bamEnums.h"
#include "dconfig.h"
class DSearchPath;
@ -36,8 +35,8 @@ NotifyCategoryDecl(bam, EXPCL_PANDA_PUTIL, EXPTP_PANDA_PUTIL);
// MemoryUsage.
//extern EXPCL_PANDA_PUTIL const bool track_memory_usage;
extern EXPCL_PANDA_PUTIL ConfigVariableEnum<BamEndian> bam_endian;
extern EXPCL_PANDA_PUTIL ConfigVariableEnum<BamTextureMode> bam_texture_mode;
extern EXPCL_PANDA_PUTIL ConfigVariableEnum<BamEnums::BamEndian> bam_endian;
extern EXPCL_PANDA_PUTIL ConfigVariableEnum<BamEnums::BamTextureMode> bam_texture_mode;
BEGIN_PUBLISH
EXPCL_PANDA_PUTIL ConfigVariableSearchPath &get_model_path();

View File

@ -27,7 +27,8 @@ TypeHandle CopyOnWriteObj1<Base, Param1>::_type_handle;
INLINE CopyOnWriteObject::
CopyOnWriteObject()
#ifdef COW_THREADED
: _lock_cvar(_lock_mutex)
: _lock_mutex("CopyOnWriteObject::_lock"),
_lock_cvar(_lock_mutex)
#endif
{
#ifdef DO_MEMORY_USAGE
@ -48,7 +49,8 @@ INLINE CopyOnWriteObject::
CopyOnWriteObject(const CopyOnWriteObject &copy) :
CachedTypedWritableReferenceCount(copy)
#ifdef COW_THREADED
, _lock_cvar(_lock_mutex)
, _lock_mutex("CopyOnWriteObject::_lock"),
_lock_cvar(_lock_mutex)
#endif
{
#ifdef DO_MEMORY_USAGE

View File

@ -21,7 +21,7 @@ TypeHandle CopyOnWriteObject::_type_handle;
#ifdef COW_THREADED
////////////////////////////////////////////////////////////////////
// Function: CopyOnWriteObject::unref
// Access: Public
// Access: Public, Virtual
// Description: Explicitly decrements the reference count. See
// ReferenceCount::unref().
//

View File

@ -49,7 +49,7 @@ public:
PUBLISHED:
#ifdef COW_THREADED
bool unref() const;
virtual bool unref() const;
INLINE void cache_ref() const;
#endif // COW_THREADED

View File

@ -140,3 +140,16 @@ is_error() {
}
return _error;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramOutputFile::flush
// Access: Public, Virtual
// Description: Ensures that all datagrams previously written will be
// visible in the output file.
////////////////////////////////////////////////////////////////////
void DatagramOutputFile::
flush() {
if (_out != (ostream *)NULL) {
_out->flush();
}
}

View File

@ -38,6 +38,7 @@ public:
bool write_header(const string &header);
virtual bool put_datagram(const Datagram &data);
virtual bool is_error();
virtual void flush();
private:
bool _wrote_first_datagram;

View File

@ -2,10 +2,9 @@
#include "bamCache.cxx"
#include "bamCacheIndex.cxx"
#include "bamCacheRecord.cxx"
#include "bamEndian.cxx"
#include "bamEnums.cxx"
#include "bamReader.cxx"
#include "bamReaderParam.cxx"
#include "bamTextureMode.cxx"
#include "bamWriter.cxx"
#include "bitArray.cxx"
#include "bitMask.cxx"

View File

@ -23,19 +23,10 @@ TypeHandle Person::_type_handle;
TypeHandle Parent::_type_handle;
TypeHandle Child::_type_handle;
ConfigureFn(config_util)
{
TypedObject::init_type();
ReferenceCount::init_type();
TypedReferenceCount::init_type();
init_system_type_handles();
FactoryParam::init_type();
Datagram::init_type();
TypedWritable::init_type();
WritableParam::init_type();
BamReaderParam::init_type();
TypedWritableReferenceCount::init_type();
Configure(config_test_bam);
ConfigureFn(config_test_bam)
{
Person::init_type();
Parent::init_type();
Child::init_type();
@ -72,17 +63,18 @@ void Person::
fillin(Person* me, DatagramIterator& scan, BamReader* manager)
{
_name = scan.get_string();
myGender = scan.get_uint8();
myGender = (Person::sex)scan.get_uint8();
manager->read_pointer(scan);
manager->read_pointer(scan);
}
int Person::
complete_pointers(TypedWritable **p_list, BamReader *)
complete_pointers(TypedWritable **p_list, BamReader *manager)
{
_bro = (p_list[0] == TypedWritable::Null) ? (Person*)NULL : DCAST(Person, p_list[0]);
_sis = (p_list[1] == TypedWritable::Null) ? (Person*)NULL : DCAST(Person, p_list[1]);
return 2;
int pi = TypedWritable::complete_pointers(p_list, manager);
_bro = DCAST(Person, p_list[pi++]);
_sis = DCAST(Person, p_list[pi++]);
return pi;
}
void Person::
@ -123,12 +115,12 @@ fillin(Parent* me, DatagramIterator& scan, BamReader* manager)
}
int Parent::
complete_pointers(TypedWritable *p_list, BamReader *manager)
complete_pointers(TypedWritable **p_list, BamReader *manager)
{
int start = Person::complete_pointers(p_list, manager);
_son = (p_list[start] == TypedWritable::Null) ? (Child*)NULL : DCAST(Child, p_list[2]);
_daughter = (p_list[start+1] == TypedWritable::Null) ? (Child*)NULL : DCAST(Child, p_list[3]);
return start+2;
int pi = Person::complete_pointers(p_list, manager);
_son = DCAST(Child, p_list[pi++]);
_daughter = DCAST(Child, p_list[pi++]);
return pi;
}
void Parent::
@ -169,7 +161,6 @@ make_child(const FactoryParams &params)
parse_params(params, scan, manager);
me->fillin(me, scan, manager);
me->fillin(me, scan, manager);
return me;
}
@ -185,10 +176,10 @@ fillin(Child* me, DatagramIterator& scan, BamReader* manager)
int Child::
complete_pointers(TypedWritable ** p_list, BamReader *manager)
{
int start = Person::complete_pointers(p_list, manager);
_dad = (p_list[start] == TypedWritable::Null) ? (Parent*)NULL : DCAST(Parent, p_list[2]);
_mom = (p_list[start+1] == TypedWritable::Null) ? (Parent*)NULL : DCAST(Parent, p_list[3]);
return start+2;
int pi = Person::complete_pointers(p_list, manager);
_dad = DCAST(Parent, p_list[pi++]);
_mom = DCAST(Parent, p_list[pi++]);
return pi;
}

View File

@ -25,8 +25,6 @@
#include "typedWritableReferenceCount.h"
#include <ipc_file.h>
class Child;
class Person : public TypedWritableReferenceCount {
@ -89,7 +87,7 @@ public:
void write_datagram(BamWriter*, Datagram&);
static TypedWritable *make_parent(const FactoryParams &params);
virtual int complete_pointers(TypedWritable *p_list,
virtual int complete_pointers(TypedWritable **p_list,
BamReader *manager);
protected:
void fillin(Parent*,DatagramIterator&,BamReader*);

View File

@ -15,16 +15,17 @@
#include "pandabase.h"
#include "pnotify.h"
#include <ipc_file.h>
#include "test_bam.h"
#include "bamReader.h"
#include "datagramInputFile.h"
int main(int argc, char* argv[])
{
string test_file = "bamTest.out";
datagram_file stream(test_file);
DatagramInputFile stream;
bool success = stream.open(test_file);
nassertr(success, 1);
stream.open(file::FILE_READ);
BamReader manager(&stream);
manager.init();
@ -44,5 +45,5 @@ int main(int argc, char* argv[])
nout << endl;
sis->print_relationships();
return 1;
return 0;
}

View File

@ -16,17 +16,16 @@
#include "pnotify.h"
#include "test_bam.h"
#include "datagramOutputFile.h"
int main(int argc, char* argv[])
{
string test_file("bamTest.out");
datagram_file stream(test_file);
DatagramOutputFile stream;
bool success = stream.open(test_file);
nassertr(success, 1);
BamWriter manager(&stream);
stream.open(file::FILE_WRITE);
// This initialization would normally be done by a ConfigureFn
// block.
PointerTo<Parent> dad = new Parent("Attila", Person::MALE);
PointerTo<Parent> mom = new Parent("Brunhilda", Person::FEMALE);
@ -56,6 +55,6 @@ int main(int argc, char* argv[])
manager.write_object(sis.p());
stream.close();
return 1;
return 0;
}

View File

@ -38,3 +38,31 @@ TypedWritable(const TypedWritable &) : _bam_writers(NULL) {
INLINE void TypedWritable::
operator = (const TypedWritable &) {
}
////////////////////////////////////////////////////////////////////
// Function: TypedWritable::mark_bam_modified
// Access: Public
// Description: Increments the bam_modified counter, so that this
// object will be invalidated and retransmitted on any
// open bam streams. This should normally not need to
// be called by user code; it should be called
// internally when the object has been changed in a way
// that legitimately requires its retransmission to any
// connected clients.
////////////////////////////////////////////////////////////////////
INLINE void TypedWritable::
mark_bam_modified() {
++_bam_modified;
}
////////////////////////////////////////////////////////////////////
// Function: TypedWritable::get_bam_modified
// Access: Public
// Description: Returns the current bam_modified counter. This
// counter is normally incremented automatically
// whenever the object is modified.
////////////////////////////////////////////////////////////////////
INLINE UpdateSeq TypedWritable::
get_bam_modified() const {
return _bam_modified;
}

View File

@ -55,6 +55,17 @@ void TypedWritable::
write_datagram(BamWriter *, Datagram &) {
}
////////////////////////////////////////////////////////////////////
// Function: TypedWritable::update_bam_nested
// Access: Public, Virtual
// Description: Called by the BamWriter when this object has not
// itself been modified recently, but it should check
// its nested objects for updates.
////////////////////////////////////////////////////////////////////
void TypedWritable::
update_bam_nested(BamWriter *) {
}
////////////////////////////////////////////////////////////////////
// Function: TypedWritable::complete_pointers
// Access: Public, Virtual
@ -97,6 +108,21 @@ require_fully_complete() const {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: TypedWritable::fillin
// Access: Public, Virtual
// Description: This internal function is intended to be called by
// each class's make_from_bam() method to read in all of
// the relevant data from the BamFile for the new
// object. It is also called directly by the BamReader
// to re-read the data for an object that has been
// placed on the stream for an update.
////////////////////////////////////////////////////////////////////
void TypedWritable::
fillin(DatagramIterator &, BamReader *) {
}
////////////////////////////////////////////////////////////////////
// Function: TypedWritable::finalize
// Access: Public, Virtual
@ -108,20 +134,13 @@ void TypedWritable::
finalize(BamReader *) {
}
////////////////////////////////////////////////////////////////////
// Function: TypedWritable::fillin
// Access: Protected
// Description: This internal function is intended to be called by
// each class's make_from_bam() method to read in all of
// the relevant data from the BamFile for the new
// object.
//
// It is defined at the TypedWritable level so that
// derived classes may call up the inheritance chain
// from their own fillin() method.
// Function: TypedWritable::as_reference_count
// Access: Public, Virtual
// Description: Returns the pointer cast to a ReferenceCount pointer,
// if it is in fact of that type.
////////////////////////////////////////////////////////////////////
void TypedWritable::
fillin(DatagramIterator &, BamReader *) {
ReferenceCount *TypedWritable::
as_reference_count() {
return NULL;
}

View File

@ -19,11 +19,13 @@
#include "vector_typedWritable.h"
#include "pvector.h"
#include "lightMutex.h"
#include "updateSeq.h"
class BamReader;
class BamWriter;
class Datagram;
class DatagramIterator;
class ReferenceCount;
////////////////////////////////////////////////////////////////////
// Class : TypedWritable
@ -43,15 +45,20 @@ public:
virtual ~TypedWritable();
virtual void write_datagram(BamWriter *, Datagram &);
virtual void write_datagram(BamWriter *manager, Datagram &dg);
virtual void update_bam_nested(BamWriter *manager);
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager);
virtual bool require_fully_complete() const;
virtual void fillin(DatagramIterator &scan, BamReader *manager);
virtual void finalize(BamReader *manager);
protected:
void fillin(DatagramIterator &scan, BamReader *manager);
virtual ReferenceCount *as_reference_count();
PUBLISHED:
INLINE void mark_bam_modified();
INLINE UpdateSeq get_bam_modified() const;
private:
// We may need to store a list of the BamWriter(s) that have a
@ -61,6 +68,8 @@ private:
BamWriters *_bam_writers;
static LightMutex _bam_writers_lock;
UpdateSeq _bam_modified;
PUBLISHED:
static TypeHandle get_class_type() {
return _type_handle;

View File

@ -15,3 +15,14 @@
#include "typedWritableReferenceCount.h"
TypeHandle TypedWritableReferenceCount::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: TypedWritableReferenceCount::as_reference_count
// Access: Public, Virtual
// Description: Returns the pointer cast to a ReferenceCount pointer,
// if it is in fact of that type.
////////////////////////////////////////////////////////////////////
ReferenceCount *TypedWritableReferenceCount::
as_reference_count() {
return this;
}

View File

@ -38,6 +38,8 @@ public:
INLINE TypedWritableReferenceCount(const TypedWritableReferenceCount &copy);
INLINE void operator = (const TypedWritableReferenceCount &copy);
virtual ReferenceCount *as_reference_count();
public:
virtual TypeHandle get_type() const {
return get_class_type();

View File

@ -149,8 +149,11 @@ get_info(const Filename &filename) {
}
if (!bam_file.resolve()) {
nout << "Unable to fully resolve file.\n";
return false;
}
bam_file.close();
// We can't close the bam file until we have examined the objects,
// since closing it will decrement reference counts.
if (objects.size() == 1 &&
objects[0]->is_of_type(PandaNode::get_class_type())) {
@ -168,6 +171,7 @@ get_info(const Filename &filename) {
describe_session(DCAST(RecorderHeader, objects[0]), objects);
} else {
nout << "file contains " << objects.size() << " objects:\n";
for (int i = 0; i < (int)objects.size(); i++) {
describe_general_object(objects[i]);
}
@ -280,6 +284,7 @@ describe_session(RecorderHeader *header, const BamInfo::Objects &objects) {
////////////////////////////////////////////////////////////////////
void BamInfo::
describe_general_object(TypedWritable *object) {
nassertv(object != (TypedWritable *)NULL);
nout << " " << object->get_type() << "\n";
}

View File

@ -40,9 +40,17 @@
#include "geom.h"
#include "geomTriangles.h"
#include "geomVertexReader.h"
#include "transformTable.h"
#include "animBundleNode.h"
#include "animChannelMatrixXfmTable.h"
#include "characterJoint.h"
#include "character.h"
#include "string_utils.h"
#include "bamFile.h"
#include "bamCacheRecord.h"
#include "eggSAnimData.h"
#include "eggXfmAnimData.h"
#include "eggXfmSAnim.h"
#include "eggGroup.h"
#include "eggVertexPool.h"
#include "eggVertex.h"
@ -51,11 +59,11 @@
#include "eggTexture.h"
#include "eggMaterial.h"
#include "eggRenderMode.h"
#include "eggTable.h"
#include "somethingToEggConverter.h"
#include "dcast.h"
#include "pystub.h"
////////////////////////////////////////////////////////////////////
// Function: BamToEgg::Constructor
// Access: Public
@ -171,6 +179,12 @@ convert_node(const WorkingNodePath &node_path, EggGroupNode *egg_parent,
} else if (node->is_of_type(CollisionNode::get_class_type())) {
convert_collision_node(DCAST(CollisionNode, node), node_path, egg_parent, has_decal);
} else if (node->is_of_type(AnimBundleNode::get_class_type())) {
convert_anim_node(DCAST(AnimBundleNode, node), node_path, egg_parent, has_decal);
} else if (node->is_of_type(Character::get_class_type())) {
convert_character_node(DCAST(Character, node), node_path, egg_parent, has_decal);
} else {
// Just a generic node.
EggGroup *egg_group = new EggGroup(node->get_name());
@ -293,6 +307,160 @@ convert_switch_node(SwitchNode *node, const WorkingNodePath &node_path,
}
}
////////////////////////////////////////////////////////////////////
// Function: BamToEgg::convert_animGroup_node
// Access: Private
// Description: Converts the indicated AnimationGroupNodes to the corresponding
// Egg constructs.
////////////////////////////////////////////////////////////////////
EggGroupNode * BamToEgg::convert_animGroup_node(AnimGroup *animGroup, double fps ) {
int num_children = animGroup->get_num_children();
EggGroupNode *eggNode = NULL;
if (animGroup->is_of_type(AnimBundle::get_class_type())) {
EggTable *eggTable = new EggTable(animGroup->get_name());
eggTable ->set_table_type(EggTable::TT_bundle);
eggNode = eggTable;
} else if (animGroup->is_of_type(AnimGroup::get_class_type())) {
EggTable *eggTable = new EggTable(animGroup->get_name());
eggTable ->set_table_type(EggTable::TT_table);
eggNode = eggTable;
}
if (animGroup->is_of_type(AnimChannelMatrixXfmTable::get_class_type())) {
AnimChannelMatrixXfmTable *xmfTable = DCAST(AnimChannelMatrixXfmTable, animGroup);
EggXfmSAnim *egg_anim = new EggXfmSAnim("xform");
egg_anim->set_fps(fps);
for (int i = 0; i < num_matrix_components; i++) {
string componentName(1, matrix_component_letters[i]);
char table_id = matrix_component_letters[i];
CPTA_float table = xmfTable ->get_table(table_id);
if (xmfTable->has_table(table_id)) {
for (unsigned int j = 0; j < table.size(); j++) {
egg_anim->add_component_data(componentName, table[j]);
}
}
}
eggNode->add_child(egg_anim);
}
for (int i = 0; i < num_children; i++) {
AnimGroup *animChild = animGroup->get_child(i);
EggGroupNode *eggChildNode = convert_animGroup_node(animChild, fps);
if (eggChildNode!=NULL) {
nassertr(eggNode!=NULL, NULL);
eggNode->add_child(eggChildNode);
}
}
return eggNode;
}
////////////////////////////////////////////////////////////////////
// Function: BamToEgg::convert_anim_node
// Access: Private
// Description: Converts the indicated AnimNode to the corresponding
// Egg constructs.
////////////////////////////////////////////////////////////////////
void BamToEgg::
convert_anim_node(AnimBundleNode *node, const WorkingNodePath &node_path,
EggGroupNode *egg_parent, bool has_decal) {
// A sequence node gets converted to an ordinary EggGroup, we only apply
// the appropriate switch attributes to turn it into a sequence
EggTable *eggTable = new EggTable();
//egg_parent->add_child(eggTable);
_data->add_child(eggTable);
AnimBundle *animBundle = node->get_bundle();
// turn it into a switch..
//egg_group->set_switch_flag(true);
EggGroupNode *eggAnimation = convert_animGroup_node(animBundle, animBundle->get_base_frame_rate());
eggTable->add_child(eggAnimation);
}
////////////////////////////////////////////////////////////////////
// Function: BamToEgg::convert_character_bundle
// Access: Private
// Description: Converts the indicated Character Bundle to the corresponding
// Egg joints structure.
////////////////////////////////////////////////////////////////////
void BamToEgg::
convert_character_bundle(PartGroup *bundleNode, EggGroupNode *egg_parent, CharacterJointMap *jointMap) {
int num_children = bundleNode->get_num_children();
EggGroupNode *joint_group = egg_parent;
if (bundleNode->is_of_type(CharacterJoint::get_class_type())) {
CharacterJoint *character_joint = DCAST(CharacterJoint, bundleNode);
LMatrix4f transformf;
character_joint->get_net_transform(transformf);
LMatrix4d transformd(LCAST(double, transformf));
EggGroup *joint = new EggGroup(bundleNode->get_name());
joint->add_matrix4(transformd);
joint->set_group_type(EggGroup::GT_joint);
joint_group = joint;
egg_parent->add_child(joint_group);
if (jointMap!=NULL) {
CharacterJointMap::iterator mi = jointMap->find(character_joint);
if (mi != jointMap->end()) {
pvector<pair<EggVertex*,float> > &joint_vertices = (*mi).second;
pvector<pair<EggVertex*,float> >::const_iterator vi;
for (vi = joint_vertices.begin(); vi != joint_vertices.end(); ++vi) {
joint->set_vertex_membership((*vi).first, (*vi).second);
}
}
}
}
for (int i = 0; i < num_children ; i++) {
PartGroup *partGroup= bundleNode->get_child(i);
convert_character_bundle(partGroup, joint_group, jointMap);
}
}
////////////////////////////////////////////////////////////////////
// Function: BamToEgg::convert_character_node
// Access: Private
// Description: Converts the indicated Character to the corresponding
// Egg constructs.
////////////////////////////////////////////////////////////////////
void BamToEgg::
convert_character_node(Character *node, const WorkingNodePath &node_path,
EggGroupNode *egg_parent, bool has_decal) {
// A sequence node gets converted to an ordinary EggGroup, we only apply
// the appropriate switch attributes to turn it into a sequence
EggGroup *egg_group = new EggGroup(node->get_name());
egg_group->set_dart_type(EggGroup::DT_default);
egg_parent->add_child(egg_group);
apply_node_properties(egg_group, node);
CharacterJointMap jointMap;
// turn it into a switch..
//egg_group->set_switch_flag(true);
int num_children = node->get_num_children();
int num_bundles = node->get_num_bundles();
for (int i = 0; i < num_children; i++) {
PandaNode *child = node->get_child(i);
if (child->is_geom_node()) {
convert_geom_node(DCAST(GeomNode, child), WorkingNodePath(node_path, child), egg_group, has_decal, &jointMap);
}
}
for (int i = 0; i < num_bundles ; i++) {
PartBundle *bundle= node->get_bundle(i);
convert_character_bundle(bundle, egg_group, &jointMap);
}
}
////////////////////////////////////////////////////////////////////
// Function: BamToEgg::convert_collision_node
// Access: Private
@ -362,7 +530,7 @@ convert_collision_node(CollisionNode *node, const WorkingNodePath &node_path,
////////////////////////////////////////////////////////////////////
void BamToEgg::
convert_geom_node(GeomNode *node, const WorkingNodePath &node_path,
EggGroupNode *egg_parent, bool has_decal) {
EggGroupNode *egg_parent, bool has_decal, CharacterJointMap *jointMap) {
PT(EggGroup) egg_group = new EggGroup(node->get_name());
bool fancy_attributes = apply_node_properties(egg_group, node);
@ -401,10 +569,10 @@ convert_geom_node(GeomNode *node, const WorkingNodePath &node_path,
CPT(GeomPrimitive) simple = primitive->decompose();
if (simple->is_of_type(GeomTriangles::get_class_type())) {
CPT(GeomVertexData) vdata = geom->get_vertex_data();
vdata = vdata->animate_vertices(true, Thread::get_current_thread());
// vdata = vdata->animate_vertices(true, Thread::get_current_thread());
convert_triangles(vdata,
DCAST(GeomTriangles, simple), geom_state,
net_mat, egg_parent);
net_mat, egg_parent, jointMap);
}
}
}
@ -421,7 +589,8 @@ void BamToEgg::
convert_triangles(const GeomVertexData *vertex_data,
const GeomTriangles *primitive,
const RenderState *net_state,
const LMatrix4f &net_mat, EggGroupNode *egg_parent) {
const LMatrix4f &net_mat, EggGroupNode *egg_parent,
CharacterJointMap *jointMap) {
GeomVertexReader reader(vertex_data);
// Check for a color scale.
@ -557,6 +726,7 @@ convert_triangles(const GeomVertexData *vertex_data,
Normalf normal;
Colorf color;
CPT(TransformBlendTable) transformBlendTable = vertex_data->get_transform_blend_table();
int nprims = primitive->get_num_primitives();
for (int i = 0; i < nprims; ++i) {
@ -607,6 +777,31 @@ convert_triangles(const GeomVertexData *vertex_data,
}
EggVertex *new_egg_vert = _vpool->create_unique_vertex(egg_vert);
if ((vertex_data->has_column(InternalName::get_transform_blend())) &&
(jointMap!=NULL) && (transformBlendTable!=NULL)) {
reader.set_column(InternalName::get_transform_blend());
int idx = reader.get_data1i();
const TransformBlend &blend = transformBlendTable->get_blend(idx);
int num_weights = blend.get_num_transforms();
for (int k = 0; k < num_weights; ++k) {
float weight = blend.get_weight(k);
if (weight!=0) {
const VertexTransform *vertex_transform = blend.get_transform(k);
if (vertex_transform->is_of_type(JointVertexTransform::get_class_type())) {
const JointVertexTransform *joint_vertex_transform = DCAST(const JointVertexTransform, vertex_transform);
CharacterJointMap::iterator mi = jointMap->find(joint_vertex_transform->get_joint());
if (mi == jointMap->end()) {
mi = jointMap->insert(CharacterJointMap::value_type(joint_vertex_transform->get_joint(), pvector<pair<EggVertex*,float> >())).first;
}
pvector<pair<EggVertex*,float> > &joint_vertices = (*mi).second;
joint_vertices.push_back(pair<EggVertex*,float>(new_egg_vert, weight));
}
}
}
}
egg_poly->add_vertex(new_egg_vert);
}
}

View File

@ -30,6 +30,10 @@ class EggTexture;
class LODNode;
class SequenceNode;
class SwitchNode;
class AnimBundleNode;
class AnimGroup;
class Character;
class PartGroup;
class CollisionNode;
class GeomNode;
class GeomTri;
@ -38,6 +42,10 @@ class GeomTriangles;
class PandaNode;
class RenderState;
class Texture;
class CharacterJoint;
class EggVertex;
typedef pmap<const CharacterJoint*, pvector<pair<EggVertex*,float> > > CharacterJointMap;
////////////////////////////////////////////////////////////////////
// Class : BamToEgg
@ -60,14 +68,21 @@ private:
EggGroupNode *egg_parent, bool has_decal);
void convert_switch_node(SwitchNode *node, const WorkingNodePath &node_path,
EggGroupNode *egg_parent, bool has_decal);
EggGroupNode *convert_animGroup_node(AnimGroup *animGroup, double fps );
void convert_anim_node(AnimBundleNode *node, const WorkingNodePath &node_path,
EggGroupNode *egg_parent, bool has_decal);
void convert_character_node(Character *node, const WorkingNodePath &node_path,
EggGroupNode *egg_parent, bool has_decal);
void convert_character_bundle(PartGroup *bundleNode, EggGroupNode *egg_parent, CharacterJointMap *jointMap);
void convert_collision_node(CollisionNode *node, const WorkingNodePath &node_path,
EggGroupNode *egg_parent, bool has_decal);
void convert_geom_node(GeomNode *node, const WorkingNodePath &node_path,
EggGroupNode *egg_parent, bool has_decal);
EggGroupNode *egg_parent, bool has_decal, CharacterJointMap *jointMap=NULL);
void convert_triangles(const GeomVertexData *vertex_data,
const GeomTriangles *primitive,
const RenderState *net_state,
const LMatrix4f &net_mat, EggGroupNode *egg_parent);
const LMatrix4f &net_mat, EggGroupNode *egg_parent,
CharacterJointMap *jointMap);
void recurse_nodes(const WorkingNodePath &node_path, EggGroupNode *egg_parent,
bool has_decal);

View File

@ -352,10 +352,10 @@ handle_args(ProgramBase::Args &args) {
// bam-texture-mode Config.prc variable directly to support this
// (otherwise the bam code will do what it wants to do anyway).
if (_tex_rawdata) {
bam_texture_mode = BTM_rawdata;
bam_texture_mode = BamFile::BTM_rawdata;
} else if (_got_path_store) {
bam_texture_mode = BTM_unchanged;
bam_texture_mode = BamFile::BTM_unchanged;
} else {
// Otherwise, the default path store is absolute; then the