mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
AttribNodeRegistry, ordering in BamReader::complete_pointers()
This commit is contained in:
parent
05e24493fc
commit
c60379d898
@ -64,7 +64,6 @@ ALLOC_DELETED_CHAIN_DEF(GeomVertexArrayDataHandle);
|
|||||||
GeomVertexArrayData::
|
GeomVertexArrayData::
|
||||||
GeomVertexArrayData() : SimpleLruPage(0) {
|
GeomVertexArrayData() : SimpleLruPage(0) {
|
||||||
_contexts = NULL;
|
_contexts = NULL;
|
||||||
_endian_reversed = false;
|
|
||||||
|
|
||||||
// Can't put it in the LRU until it has been read in and made valid.
|
// Can't put it in the LRU until it has been read in and made valid.
|
||||||
}
|
}
|
||||||
@ -97,7 +96,6 @@ GeomVertexArrayData(const GeomVertexArrayFormat *array_format,
|
|||||||
CLOSE_ITERATE_ALL_STAGES(_cycler);
|
CLOSE_ITERATE_ALL_STAGES(_cycler);
|
||||||
|
|
||||||
_contexts = NULL;
|
_contexts = NULL;
|
||||||
_endian_reversed = false;
|
|
||||||
|
|
||||||
set_lru_size(0);
|
set_lru_size(0);
|
||||||
nassertv(_array_format->is_registered());
|
nassertv(_array_format->is_registered());
|
||||||
@ -116,7 +114,6 @@ GeomVertexArrayData(const GeomVertexArrayData ©) :
|
|||||||
_cycler(copy._cycler)
|
_cycler(copy._cycler)
|
||||||
{
|
{
|
||||||
_contexts = NULL;
|
_contexts = NULL;
|
||||||
_endian_reversed = false;
|
|
||||||
|
|
||||||
copy.mark_used_lru();
|
copy.mark_used_lru();
|
||||||
|
|
||||||
@ -511,12 +508,15 @@ finalize(BamReader *manager) {
|
|||||||
manager->change_pointer(_array_format, new_array_format);
|
manager->change_pointer(_array_format, new_array_format);
|
||||||
_array_format = new_array_format;
|
_array_format = new_array_format;
|
||||||
|
|
||||||
if (_endian_reversed) {
|
PT(BamAuxData) aux_data = (BamAuxData *)manager->get_aux_data(this, "");
|
||||||
|
if (aux_data != (BamAuxData *)NULL) {
|
||||||
|
if (aux_data->_endian_reversed) {
|
||||||
// Now is the time to endian-reverse the data.
|
// Now is the time to endian-reverse the data.
|
||||||
VertexDataBuffer new_buffer(cdata->_buffer.get_size());
|
VertexDataBuffer new_buffer(cdata->_buffer.get_size());
|
||||||
reverse_data_endianness(new_buffer.get_write_pointer(), cdata->_buffer.get_read_pointer(true), cdata->_buffer.get_size());
|
reverse_data_endianness(new_buffer.get_write_pointer(), cdata->_buffer.get_read_pointer(true), cdata->_buffer.get_size());
|
||||||
cdata->_buffer.swap(new_buffer);
|
cdata->_buffer.swap(new_buffer);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
set_lru_size(cdata->_buffer.get_size());
|
set_lru_size(cdata->_buffer.get_size());
|
||||||
}
|
}
|
||||||
@ -632,13 +632,15 @@ fillin(DatagramIterator &scan, BamReader *manager, void *extra_data) {
|
|||||||
scan.skip_bytes(size);
|
scan.skip_bytes(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool endian_reversed = false;
|
||||||
|
|
||||||
if (manager->get_file_endian() != BE_native) {
|
if (manager->get_file_endian() != BE_native) {
|
||||||
// For non-native endian files, we have to convert the data.
|
// For non-native endian files, we have to convert the data.
|
||||||
|
|
||||||
if (array_data->_array_format == (GeomVertexArrayFormat *)NULL) {
|
if (array_data->_array_format == (GeomVertexArrayFormat *)NULL) {
|
||||||
// But we can't do that until we've completed the _array_format
|
// But we can't do that until we've completed the _array_format
|
||||||
// pointer, which tells us how to convert it.
|
// pointer, which tells us how to convert it.
|
||||||
array_data->_endian_reversed = true;
|
endian_reversed = true;
|
||||||
} else {
|
} else {
|
||||||
// Since we have the _array_format pointer now, we can reverse
|
// Since we have the _array_format pointer now, we can reverse
|
||||||
// it immediately (and we should, to support threaded CData
|
// it immediately (and we should, to support threaded CData
|
||||||
@ -649,6 +651,12 @@ fillin(DatagramIterator &scan, BamReader *manager, void *extra_data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (endian_reversed) {
|
||||||
|
PT(BamAuxData) aux_data = new BamAuxData;
|
||||||
|
aux_data->_endian_reversed = endian_reversed;
|
||||||
|
manager->set_aux_data(array_data, "", aux_data);
|
||||||
|
}
|
||||||
|
|
||||||
array_data->set_lru_size(_buffer.get_size());
|
array_data->set_lru_size(_buffer.get_size());
|
||||||
|
|
||||||
_modified = Geom::get_next_modified();
|
_modified = Geom::get_next_modified();
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include "simpleLru.h"
|
#include "simpleLru.h"
|
||||||
#include "vertexDataBuffer.h"
|
#include "vertexDataBuffer.h"
|
||||||
#include "config_gobj.h"
|
#include "config_gobj.h"
|
||||||
|
#include "bamReader.h"
|
||||||
|
|
||||||
class PreparedGraphicsObjects;
|
class PreparedGraphicsObjects;
|
||||||
class VertexBufferContext;
|
class VertexBufferContext;
|
||||||
@ -135,9 +136,13 @@ private:
|
|||||||
typedef pmap<PreparedGraphicsObjects *, VertexBufferContext *> Contexts;
|
typedef pmap<PreparedGraphicsObjects *, VertexBufferContext *> Contexts;
|
||||||
Contexts *_contexts;
|
Contexts *_contexts;
|
||||||
|
|
||||||
// This is only used when reading from a bam file. It is set true
|
// This data is only needed when reading from a bam file.
|
||||||
// to indicate the data must be endian-reversed in finalize().
|
class BamAuxData : public BamReader::AuxData {
|
||||||
|
public:
|
||||||
|
// set true to indicate the data must be endian-reversed in
|
||||||
|
// finalize().
|
||||||
bool _endian_reversed;
|
bool _endian_reversed;
|
||||||
|
};
|
||||||
|
|
||||||
// This is the data that must be cycled between pipeline stages.
|
// This is the data that must be cycled between pipeline stages.
|
||||||
class EXPCL_PANDA CData : public CycleData {
|
class EXPCL_PANDA CData : public CycleData {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
alphaTestAttrib.I alphaTestAttrib.h \
|
alphaTestAttrib.I alphaTestAttrib.h \
|
||||||
ambientLight.I ambientLight.h \
|
ambientLight.I ambientLight.h \
|
||||||
antialiasAttrib.I antialiasAttrib.h \
|
antialiasAttrib.I antialiasAttrib.h \
|
||||||
|
attribNodeRegistry.I attribNodeRegistry.h \
|
||||||
attribSlots.h attribSlots.I \
|
attribSlots.h attribSlots.I \
|
||||||
audioVolumeAttrib.I audioVolumeAttrib.h \
|
audioVolumeAttrib.I audioVolumeAttrib.h \
|
||||||
auxSceneData.I auxSceneData.h \
|
auxSceneData.I auxSceneData.h \
|
||||||
@ -127,6 +128,7 @@
|
|||||||
alphaTestAttrib.cxx \
|
alphaTestAttrib.cxx \
|
||||||
ambientLight.cxx \
|
ambientLight.cxx \
|
||||||
antialiasAttrib.cxx \
|
antialiasAttrib.cxx \
|
||||||
|
attribNodeRegistry.cxx \
|
||||||
attribSlots.cxx \
|
attribSlots.cxx \
|
||||||
audioVolumeAttrib.cxx \
|
audioVolumeAttrib.cxx \
|
||||||
auxSceneData.cxx \
|
auxSceneData.cxx \
|
||||||
@ -232,6 +234,7 @@
|
|||||||
alphaTestAttrib.I alphaTestAttrib.h \
|
alphaTestAttrib.I alphaTestAttrib.h \
|
||||||
ambientLight.I ambientLight.h \
|
ambientLight.I ambientLight.h \
|
||||||
antialiasAttrib.I antialiasAttrib.h \
|
antialiasAttrib.I antialiasAttrib.h \
|
||||||
|
attribNodeRegistry.I attribNodeRegistry.h \
|
||||||
attribSlots.h attribSlots.I \
|
attribSlots.h attribSlots.I \
|
||||||
audioVolumeAttrib.I audioVolumeAttrib.h \
|
audioVolumeAttrib.I audioVolumeAttrib.h \
|
||||||
auxSceneData.I auxSceneData.h \
|
auxSceneData.I auxSceneData.h \
|
||||||
|
69
panda/src/pgraph/attribNodeRegistry.I
Normal file
69
panda/src/pgraph/attribNodeRegistry.I
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// Filename: attribNodeRegistry.I
|
||||||
|
// Created by: drose (07Jul07)
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// PANDA 3D SOFTWARE
|
||||||
|
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||||
|
//
|
||||||
|
// All use of this software is subject to the terms of the Panda 3d
|
||||||
|
// Software license. You should have received a copy of this license
|
||||||
|
// along with this source code; you will also find a current copy of
|
||||||
|
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||||
|
//
|
||||||
|
// To contact the maintainers of this program write to
|
||||||
|
// panda3d-general@lists.sourceforge.net .
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: AttribNodeRegistry::get_global_ptr
|
||||||
|
// Access: Published, Static
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE AttribNodeRegistry *AttribNodeRegistry::
|
||||||
|
get_global_ptr() {
|
||||||
|
if (_global_ptr == (AttribNodeRegistry *)NULL) {
|
||||||
|
make_global_ptr();
|
||||||
|
}
|
||||||
|
return _global_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: AttribNodeRegistry::Entry::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE AttribNodeRegistry::Entry::
|
||||||
|
Entry(const NodePath &node) :
|
||||||
|
_type(node.node()->get_type()),
|
||||||
|
_name(node.get_name()),
|
||||||
|
_node(node)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: AttribNodeRegistry::Entry::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE AttribNodeRegistry::Entry::
|
||||||
|
Entry(TypeHandle type, const string &name) :
|
||||||
|
_type(type),
|
||||||
|
_name(name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: AttribNodeRegistry::Entry::operator <
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE bool AttribNodeRegistry::Entry::
|
||||||
|
operator < (const Entry &other) const {
|
||||||
|
if (_type != other._type) {
|
||||||
|
return _type < other._type;
|
||||||
|
}
|
||||||
|
return _name < other._name;
|
||||||
|
}
|
275
panda/src/pgraph/attribNodeRegistry.cxx
Normal file
275
panda/src/pgraph/attribNodeRegistry.cxx
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
// Filename: attribNodeRegistry.cxx
|
||||||
|
// Created by: drose (07Jul07)
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// PANDA 3D SOFTWARE
|
||||||
|
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||||
|
//
|
||||||
|
// All use of this software is subject to the terms of the Panda 3d
|
||||||
|
// Software license. You should have received a copy of this license
|
||||||
|
// along with this source code; you will also find a current copy of
|
||||||
|
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||||
|
//
|
||||||
|
// To contact the maintainers of this program write to
|
||||||
|
// panda3d-general@lists.sourceforge.net .
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "attribNodeRegistry.h"
|
||||||
|
#include "mutexHolder.h"
|
||||||
|
|
||||||
|
AttribNodeRegistry * TVOLATILE AttribNodeRegistry::_global_ptr;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: AttribNodeRegistry::Constructor
|
||||||
|
// Access: Protected
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
AttribNodeRegistry::
|
||||||
|
AttribNodeRegistry() {
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: AttribNodeRegistry::add_node
|
||||||
|
// Access: Published
|
||||||
|
// Description: Adds the indicated NodePath to the registry. The
|
||||||
|
// name and type of the node are noted at the time of
|
||||||
|
// this call; if the name changes later, it will not
|
||||||
|
// update the registry index.
|
||||||
|
//
|
||||||
|
// The NodePath must reference some kind of an attribute
|
||||||
|
// node, such as a LightNode or a PlaneNode. When bam
|
||||||
|
// files that reference an attribute node of the same
|
||||||
|
// type and the same name are loaded, they will quietly
|
||||||
|
// be redirected to reference this NodePath.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void AttribNodeRegistry::
|
||||||
|
add_node(const NodePath &attrib_node) {
|
||||||
|
nassertv(!attrib_node.is_empty());
|
||||||
|
MutexHolder holder(_lock);
|
||||||
|
_entries.insert(Entry(attrib_node));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: AttribNodeRegistry::remove_node
|
||||||
|
// Access: Published
|
||||||
|
// Description: Removes the indicated NodePath from the registry.
|
||||||
|
// The name of the node must not have changed since the
|
||||||
|
// matching call to add_node(), or it will not be
|
||||||
|
// successfully removed.
|
||||||
|
//
|
||||||
|
// Returns true if the NodePath is found and removed,
|
||||||
|
// false if it is not found (for instance, because the
|
||||||
|
// name has changed).
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool AttribNodeRegistry::
|
||||||
|
remove_node(const NodePath &attrib_node) {
|
||||||
|
nassertr(!attrib_node.is_empty(), false);
|
||||||
|
MutexHolder holder(_lock);
|
||||||
|
Entries::iterator ei = _entries.find(Entry(attrib_node));
|
||||||
|
if (ei != _entries.end()) {
|
||||||
|
_entries.erase(ei);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: AttribNodeRegistry::lookup_node
|
||||||
|
// Access: Published
|
||||||
|
// Description: Looks up the indicated NodePath in the registry. If
|
||||||
|
// there is a node already in the registry with the
|
||||||
|
// matching name and type, returns that NodePath
|
||||||
|
// instead; otherwise, returns the original NodePath.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
NodePath AttribNodeRegistry::
|
||||||
|
lookup_node(const NodePath &orig_node) const {
|
||||||
|
nassertr(!orig_node.is_empty(), orig_node);
|
||||||
|
|
||||||
|
MutexHolder holder(_lock);
|
||||||
|
Entries::const_iterator ei = _entries.find(Entry(orig_node));
|
||||||
|
if (ei != _entries.end()) {
|
||||||
|
return (*ei)._node;
|
||||||
|
}
|
||||||
|
return orig_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: AttribNodeRegistry::get_num_nodes
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the total number of nodes in the registry.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
int AttribNodeRegistry::
|
||||||
|
get_num_nodes() const {
|
||||||
|
MutexHolder holder(_lock);
|
||||||
|
return _entries.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: AttribNodeRegistry::get_node
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the nth NodePath recorded in the registry.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
NodePath AttribNodeRegistry::
|
||||||
|
get_node(int n) const {
|
||||||
|
MutexHolder holder(_lock);
|
||||||
|
nassertr(n >= 0 && n < (int)_entries.size(), NodePath());
|
||||||
|
return _entries[n]._node;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: AttribNodeRegistry::get_node_type
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the type of the nth node, as recorded in the
|
||||||
|
// registry.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
TypeHandle AttribNodeRegistry::
|
||||||
|
get_node_type(int n) const {
|
||||||
|
MutexHolder holder(_lock);
|
||||||
|
nassertr(n >= 0 && n < (int)_entries.size(), TypeHandle::none());
|
||||||
|
return _entries[n]._type;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: AttribNodeRegistry::get_node_name
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the name of the nth node, as recorded in the
|
||||||
|
// registry. This will be the node name as it was at
|
||||||
|
// the time the node was recorded; if the node has
|
||||||
|
// changed names since then, this will still return the
|
||||||
|
// original name.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
string AttribNodeRegistry::
|
||||||
|
get_node_name(int n) const {
|
||||||
|
MutexHolder holder(_lock);
|
||||||
|
nassertr(n >= 0 && n < (int)_entries.size(), string());
|
||||||
|
return _entries[n]._name;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: AttribNodeRegistry::find_node
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the index number of the indicated NodePath in
|
||||||
|
// the registry (assuming its name hasn't changed since
|
||||||
|
// it was recorded in the registry), or -1 if the
|
||||||
|
// NodePath cannot be found (for instance, because its
|
||||||
|
// name has changed).
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
int AttribNodeRegistry::
|
||||||
|
find_node(const NodePath &attrib_node) const {
|
||||||
|
nassertr(!attrib_node.is_empty(), -1);
|
||||||
|
MutexHolder holder(_lock);
|
||||||
|
Entries::const_iterator ei = _entries.find(Entry(attrib_node));
|
||||||
|
if (ei != _entries.end()) {
|
||||||
|
return ei - _entries.begin();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: AttribNodeRegistry::find_node
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the index number of the node with the
|
||||||
|
// indicated type and name in the registry, or -1 if
|
||||||
|
// there is no such node in the registry.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
int AttribNodeRegistry::
|
||||||
|
find_node(TypeHandle type, const string &name) const {
|
||||||
|
MutexHolder holder(_lock);
|
||||||
|
Entries::const_iterator ei = _entries.find(Entry(type, name));
|
||||||
|
if (ei != _entries.end()) {
|
||||||
|
return ei - _entries.begin();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: AttribNodeRegistry::remove_node
|
||||||
|
// Access: Published
|
||||||
|
// Description: Removes the nth node from the registry.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void AttribNodeRegistry::
|
||||||
|
remove_node(int n) {
|
||||||
|
MutexHolder holder(_lock);
|
||||||
|
nassertv(n >= 0 && n < (int)_entries.size());
|
||||||
|
_entries.erase(_entries.begin() + n);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: AttribNodeRegistry::clear
|
||||||
|
// Access: Published
|
||||||
|
// Description: Removes all nodes from the registry.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void AttribNodeRegistry::
|
||||||
|
clear() {
|
||||||
|
MutexHolder holder(_lock);
|
||||||
|
_entries.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: AttribNodeRegistry::output
|
||||||
|
// Access: Published
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void AttribNodeRegistry::
|
||||||
|
output(ostream &out) const {
|
||||||
|
MutexHolder holder(_lock);
|
||||||
|
|
||||||
|
typedef pmap<TypeHandle, int> Counts;
|
||||||
|
Counts counts;
|
||||||
|
|
||||||
|
Entries::const_iterator ei;
|
||||||
|
for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
|
||||||
|
TypeHandle type = (*ei)._type;
|
||||||
|
Counts::iterator ci = counts.insert(Counts::value_type(type, 0)).first;
|
||||||
|
++((*ci).second);
|
||||||
|
}
|
||||||
|
|
||||||
|
out << _entries.size() << " entries";
|
||||||
|
|
||||||
|
if (!counts.empty()) {
|
||||||
|
Counts::iterator ci = counts.begin();
|
||||||
|
out << " (" << (*ci).first << ":" << (*ci).second;
|
||||||
|
++ci;
|
||||||
|
while (ci != counts.end()) {
|
||||||
|
out << ", " << (*ci).first << ":" << (*ci).second;
|
||||||
|
++ci;
|
||||||
|
}
|
||||||
|
out << ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: AttribNodeRegistry::write
|
||||||
|
// Access: Published
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void AttribNodeRegistry::
|
||||||
|
write(ostream &out) const {
|
||||||
|
MutexHolder holder(_lock);
|
||||||
|
|
||||||
|
Entries::const_iterator ei;
|
||||||
|
for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
|
||||||
|
const Entry &entry = (*ei);
|
||||||
|
out << entry._type << ", \"" << entry._name << "\": " << entry._node
|
||||||
|
<< "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: AttribNodeRegistry::make_global_ptr
|
||||||
|
// Access: Private, Static
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void AttribNodeRegistry::
|
||||||
|
make_global_ptr() {
|
||||||
|
AttribNodeRegistry *ptr = new AttribNodeRegistry;
|
||||||
|
void *result = AtomicAdjust::compare_and_exchange_ptr
|
||||||
|
((void * TVOLATILE &)_global_ptr, (void *)NULL, (void *)ptr);
|
||||||
|
if (result != NULL) {
|
||||||
|
// Someone else got there first.
|
||||||
|
delete ptr;
|
||||||
|
}
|
||||||
|
assert(_global_ptr != (AttribNodeRegistry *)NULL);
|
||||||
|
}
|
91
panda/src/pgraph/attribNodeRegistry.h
Normal file
91
panda/src/pgraph/attribNodeRegistry.h
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
// Filename: attribNodeRegistry.h
|
||||||
|
// Created by: drose (07Jul07)
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// PANDA 3D SOFTWARE
|
||||||
|
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||||
|
//
|
||||||
|
// All use of this software is subject to the terms of the Panda 3d
|
||||||
|
// Software license. You should have received a copy of this license
|
||||||
|
// along with this source code; you will also find a current copy of
|
||||||
|
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||||
|
//
|
||||||
|
// To contact the maintainers of this program write to
|
||||||
|
// panda3d-general@lists.sourceforge.net .
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef ATTRIBNODEREGISTRY_H
|
||||||
|
#define ATTRIBNODEREGISTRY_H
|
||||||
|
|
||||||
|
#include "pandabase.h"
|
||||||
|
#include "nodePath.h"
|
||||||
|
#include "ordered_vector.h"
|
||||||
|
#include "pmutex.h"
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Class : AttribNodeRegistry
|
||||||
|
// Description : This global object records NodePaths that are
|
||||||
|
// referenced by scene graph attribs, such as
|
||||||
|
// ClipPlaneAttribs and LightAttribs.
|
||||||
|
//
|
||||||
|
// Its primary purpose is to unify attribs that are
|
||||||
|
// loaded in from bam files. Attrib nodes are
|
||||||
|
// identified by name and type; when a bam file that
|
||||||
|
// contains references to some attrib nodes is loaded,
|
||||||
|
// those nodes are first looked up here in the
|
||||||
|
// AttribNodeRegistry. If there is a match (by name and
|
||||||
|
// node type), the identified node is used instead of
|
||||||
|
// the node referenced within the bam file itself.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
class EXPCL_PANDA AttribNodeRegistry {
|
||||||
|
protected:
|
||||||
|
AttribNodeRegistry();
|
||||||
|
|
||||||
|
PUBLISHED:
|
||||||
|
void add_node(const NodePath &attrib_node);
|
||||||
|
bool remove_node(const NodePath &attrib_node);
|
||||||
|
NodePath lookup_node(const NodePath &orig_node) const;
|
||||||
|
|
||||||
|
int get_num_nodes() const;
|
||||||
|
NodePath get_node(int n) const;
|
||||||
|
TypeHandle get_node_type(int n) const;
|
||||||
|
string get_node_name(int n) const;
|
||||||
|
|
||||||
|
int find_node(const NodePath &attrib_node) const;
|
||||||
|
int find_node(TypeHandle type, const string &name) const;
|
||||||
|
void remove_node(int n);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
void output(ostream &out) const;
|
||||||
|
void write(ostream &out) const;
|
||||||
|
|
||||||
|
INLINE static AttribNodeRegistry *get_global_ptr();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void make_global_ptr();
|
||||||
|
|
||||||
|
class Entry {
|
||||||
|
public:
|
||||||
|
INLINE Entry(const NodePath &node);
|
||||||
|
INLINE Entry(TypeHandle type, const string &name);
|
||||||
|
INLINE bool operator < (const Entry &other) const;
|
||||||
|
|
||||||
|
TypeHandle _type;
|
||||||
|
string _name;
|
||||||
|
NodePath _node;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef ov_set<Entry> Entries;
|
||||||
|
Entries _entries;
|
||||||
|
|
||||||
|
Mutex _lock;
|
||||||
|
|
||||||
|
static AttribNodeRegistry * TVOLATILE _global_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "attribNodeRegistry.I"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -25,6 +25,7 @@
|
|||||||
#include "datagram.h"
|
#include "datagram.h"
|
||||||
#include "datagramIterator.h"
|
#include "datagramIterator.h"
|
||||||
#include "config_pgraph.h"
|
#include "config_pgraph.h"
|
||||||
|
#include "attribNodeRegistry.h"
|
||||||
|
|
||||||
CPT(RenderAttrib) ClipPlaneAttrib::_empty_attrib;
|
CPT(RenderAttrib) ClipPlaneAttrib::_empty_attrib;
|
||||||
CPT(RenderAttrib) ClipPlaneAttrib::_all_off_attrib;
|
CPT(RenderAttrib) ClipPlaneAttrib::_all_off_attrib;
|
||||||
@ -937,7 +938,9 @@ write_datagram(BamWriter *manager, Datagram &dg) {
|
|||||||
for (fi = _off_planes.begin(); fi != _off_planes.end(); ++fi) {
|
for (fi = _off_planes.begin(); fi != _off_planes.end(); ++fi) {
|
||||||
NodePath plane = (*fi);
|
NodePath plane = (*fi);
|
||||||
|
|
||||||
// Whoops, we don't have a way to write out a NodePath right now.
|
// Since we can't write out a NodePath, we write out just the
|
||||||
|
// plain PandaNode. The user can use the AttribNodeRegistry on
|
||||||
|
// re-read if there is any ambiguity that needs to be resolved.
|
||||||
manager->write_pointer(dg, plane.node());
|
manager->write_pointer(dg, plane.node());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -961,28 +964,46 @@ write_datagram(BamWriter *manager, Datagram &dg) {
|
|||||||
int ClipPlaneAttrib::
|
int ClipPlaneAttrib::
|
||||||
complete_pointers(TypedWritable **p_list, BamReader *manager) {
|
complete_pointers(TypedWritable **p_list, BamReader *manager) {
|
||||||
int pi = RenderAttrib::complete_pointers(p_list, manager);
|
int pi = RenderAttrib::complete_pointers(p_list, manager);
|
||||||
|
AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr();
|
||||||
|
|
||||||
Planes::iterator ci = _off_planes.begin();
|
Planes::iterator ci = _off_planes.begin();
|
||||||
while (ci != _off_planes.end()) {
|
while (ci != _off_planes.end()) {
|
||||||
PandaNode *node;
|
PandaNode *node;
|
||||||
DCAST_INTO_R(node, p_list[pi++], pi);
|
DCAST_INTO_R(node, p_list[pi++], pi);
|
||||||
NodePath np(node);
|
NodePath np(node);
|
||||||
(*ci) = np;
|
(*ci) = areg->lookup_node(np);
|
||||||
++ci;
|
++ci;
|
||||||
}
|
}
|
||||||
|
_off_planes.sort();
|
||||||
|
|
||||||
ci = _on_planes.begin();
|
ci = _on_planes.begin();
|
||||||
while (ci != _on_planes.end()) {
|
while (ci != _on_planes.end()) {
|
||||||
PandaNode *node;
|
PandaNode *node;
|
||||||
DCAST_INTO_R(node, p_list[pi++], pi);
|
DCAST_INTO_R(node, p_list[pi++], pi);
|
||||||
NodePath np(node);
|
NodePath np(node);
|
||||||
(*ci) = np;
|
(*ci) = areg->lookup_node(np);
|
||||||
++ci;
|
++ci;
|
||||||
}
|
}
|
||||||
|
_on_planes.sort();
|
||||||
|
|
||||||
return pi;
|
return pi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: ClipPlaneAttrib::require_fully_complete
|
||||||
|
// Access: Public, Virtual
|
||||||
|
// Description: Some objects require all of their nested pointers to
|
||||||
|
// have been completed before the objects themselves can
|
||||||
|
// be completed. If this is the case, override this
|
||||||
|
// method to return true, and be careful with circular
|
||||||
|
// references (which would make the object unreadable
|
||||||
|
// from a bam file).
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool ClipPlaneAttrib::
|
||||||
|
require_fully_complete() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: ClipPlaneAttrib::make_from_bam
|
// Function: ClipPlaneAttrib::make_from_bam
|
||||||
// Access: Protected, Static
|
// Access: Protected, Static
|
||||||
@ -1026,19 +1047,19 @@ fillin(DatagramIterator &scan, BamReader *manager) {
|
|||||||
|
|
||||||
int num_off_planes = scan.get_uint16();
|
int num_off_planes = scan.get_uint16();
|
||||||
|
|
||||||
// Push back a NULL pointer for each off Plane for now, until
|
// Push back an empty NodePath for each off Plane for now, until we
|
||||||
// we get the actual list of pointers later in complete_pointers().
|
// get the actual list of pointers later in complete_pointers().
|
||||||
_off_planes.reserve(num_off_planes);
|
_off_planes.reserve(num_off_planes);
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < num_off_planes; i++) {
|
for (i = 0; i < num_off_planes; i++) {
|
||||||
manager->read_pointer(scan);
|
manager->read_pointer(scan);
|
||||||
_off_planes.push_back(NULL);
|
_off_planes.push_back(NodePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
int num_on_planes = scan.get_uint16();
|
int num_on_planes = scan.get_uint16();
|
||||||
_on_planes.reserve(num_on_planes);
|
_on_planes.reserve(num_on_planes);
|
||||||
for (i = 0; i < num_on_planes; i++) {
|
for (i = 0; i < num_on_planes; i++) {
|
||||||
manager->read_pointer(scan);
|
manager->read_pointer(scan);
|
||||||
_on_planes.push_back(NULL);
|
_on_planes.push_back(NodePath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,6 +127,7 @@ public:
|
|||||||
static void register_with_read_factory();
|
static void register_with_read_factory();
|
||||||
virtual void write_datagram(BamWriter *manager, Datagram &dg);
|
virtual void write_datagram(BamWriter *manager, Datagram &dg);
|
||||||
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
|
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
|
||||||
|
virtual bool require_fully_complete() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static TypedWritable *make_from_bam(const FactoryParams ¶ms);
|
static TypedWritable *make_from_bam(const FactoryParams ¶ms);
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "datagram.h"
|
#include "datagram.h"
|
||||||
#include "datagramIterator.h"
|
#include "datagramIterator.h"
|
||||||
#include "config_pgraph.h"
|
#include "config_pgraph.h"
|
||||||
|
#include "attribNodeRegistry.h"
|
||||||
|
|
||||||
CPT(RenderAttrib) LightAttrib::_empty_attrib;
|
CPT(RenderAttrib) LightAttrib::_empty_attrib;
|
||||||
CPT(RenderAttrib) LightAttrib::_all_off_attrib;
|
CPT(RenderAttrib) LightAttrib::_all_off_attrib;
|
||||||
@ -916,7 +917,9 @@ write_datagram(BamWriter *manager, Datagram &dg) {
|
|||||||
for (fi = _off_lights.begin(); fi != _off_lights.end(); ++fi) {
|
for (fi = _off_lights.begin(); fi != _off_lights.end(); ++fi) {
|
||||||
NodePath light = (*fi);
|
NodePath light = (*fi);
|
||||||
|
|
||||||
// Whoops, we don't have a way to write out a NodePath right now.
|
// Since we can't write out a NodePath, we write out just the
|
||||||
|
// plain PandaNode. The user can use the AttribNodeRegistry on
|
||||||
|
// re-read if there is any ambiguity that needs to be resolved.
|
||||||
manager->write_pointer(dg, light.node());
|
manager->write_pointer(dg, light.node());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -940,28 +943,46 @@ write_datagram(BamWriter *manager, Datagram &dg) {
|
|||||||
int LightAttrib::
|
int LightAttrib::
|
||||||
complete_pointers(TypedWritable **p_list, BamReader *manager) {
|
complete_pointers(TypedWritable **p_list, BamReader *manager) {
|
||||||
int pi = RenderAttrib::complete_pointers(p_list, manager);
|
int pi = RenderAttrib::complete_pointers(p_list, manager);
|
||||||
|
AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr();
|
||||||
|
|
||||||
Lights::iterator ci = _off_lights.begin();
|
Lights::iterator ci = _off_lights.begin();
|
||||||
while (ci != _off_lights.end()) {
|
while (ci != _off_lights.end()) {
|
||||||
PandaNode *node;
|
PandaNode *node;
|
||||||
DCAST_INTO_R(node, p_list[pi++], pi);
|
DCAST_INTO_R(node, p_list[pi++], pi);
|
||||||
NodePath np(node);
|
NodePath np(node);
|
||||||
(*ci) = np;
|
(*ci) = areg->lookup_node(np);
|
||||||
++ci;
|
++ci;
|
||||||
}
|
}
|
||||||
|
_off_lights.sort();
|
||||||
|
|
||||||
ci = _on_lights.begin();
|
ci = _on_lights.begin();
|
||||||
while (ci != _on_lights.end()) {
|
while (ci != _on_lights.end()) {
|
||||||
PandaNode *node;
|
PandaNode *node;
|
||||||
DCAST_INTO_R(node, p_list[pi++], pi);
|
DCAST_INTO_R(node, p_list[pi++], pi);
|
||||||
NodePath np(node);
|
NodePath np(node);
|
||||||
(*ci) = np;
|
(*ci) = areg->lookup_node(np);
|
||||||
++ci;
|
++ci;
|
||||||
}
|
}
|
||||||
|
_on_lights.sort();
|
||||||
|
|
||||||
return pi;
|
return pi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: LightAttrib::require_fully_complete
|
||||||
|
// Access: Public, Virtual
|
||||||
|
// Description: Some objects require all of their nested pointers to
|
||||||
|
// have been completed before the objects themselves can
|
||||||
|
// be completed. If this is the case, override this
|
||||||
|
// method to return true, and be careful with circular
|
||||||
|
// references (which would make the object unreadable
|
||||||
|
// from a bam file).
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool LightAttrib::
|
||||||
|
require_fully_complete() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: LightAttrib::make_from_bam
|
// Function: LightAttrib::make_from_bam
|
||||||
// Access: Protected, Static
|
// Access: Protected, Static
|
||||||
@ -1005,19 +1026,19 @@ fillin(DatagramIterator &scan, BamReader *manager) {
|
|||||||
|
|
||||||
int num_off_lights = scan.get_uint16();
|
int num_off_lights = scan.get_uint16();
|
||||||
|
|
||||||
// Push back a NULL pointer for each off Light for now, until
|
// Push back an empty NodePath for each off Light for now, until we
|
||||||
// we get the actual list of pointers later in complete_pointers().
|
// get the actual list of pointers later in complete_pointers().
|
||||||
_off_lights.reserve(num_off_lights);
|
_off_lights.reserve(num_off_lights);
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < num_off_lights; i++) {
|
for (i = 0; i < num_off_lights; i++) {
|
||||||
manager->read_pointer(scan);
|
manager->read_pointer(scan);
|
||||||
_off_lights.push_back(NULL);
|
_off_lights.push_back(NodePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
int num_on_lights = scan.get_uint16();
|
int num_on_lights = scan.get_uint16();
|
||||||
_on_lights.reserve(num_on_lights);
|
_on_lights.reserve(num_on_lights);
|
||||||
for (i = 0; i < num_on_lights; i++) {
|
for (i = 0; i < num_on_lights; i++) {
|
||||||
manager->read_pointer(scan);
|
manager->read_pointer(scan);
|
||||||
_on_lights.push_back(NULL);
|
_on_lights.push_back(NodePath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,6 +125,7 @@ public:
|
|||||||
static void register_with_read_factory();
|
static void register_with_read_factory();
|
||||||
virtual void write_datagram(BamWriter *manager, Datagram &dg);
|
virtual void write_datagram(BamWriter *manager, Datagram &dg);
|
||||||
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
|
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
|
||||||
|
virtual bool require_fully_complete() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static TypedWritable *make_from_bam(const FactoryParams ¶ms);
|
static TypedWritable *make_from_bam(const FactoryParams ¶ms);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "accumulatedAttribs.cxx"
|
#include "accumulatedAttribs.cxx"
|
||||||
#include "ambientLight.cxx"
|
#include "ambientLight.cxx"
|
||||||
#include "antialiasAttrib.cxx"
|
#include "antialiasAttrib.cxx"
|
||||||
|
#include "attribNodeRegistry.cxx"
|
||||||
#include "audioVolumeAttrib.cxx"
|
#include "audioVolumeAttrib.cxx"
|
||||||
#include "auxSceneData.cxx"
|
#include "auxSceneData.cxx"
|
||||||
#include "attribSlots.cxx"
|
#include "attribSlots.cxx"
|
||||||
|
@ -173,6 +173,15 @@ get_datagram(Datagram &datagram) {
|
|||||||
return _source->get_datagram(datagram);
|
return _source->get_datagram(datagram);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: BamReader::AuxData::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE BamReader::AuxData::
|
||||||
|
AuxData() {
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: parse_params
|
// Function: parse_params
|
||||||
// Access: Private, Static
|
// Access: Private, Static
|
||||||
|
@ -135,20 +135,44 @@ init() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: BamReader::set_aux_data
|
// Function: BamReader::set_aux_data
|
||||||
// Access: Public
|
// Access: Public
|
||||||
// Description: Associates an arbitrary pointer to the bam reader
|
// Description: Associates an arbitrary block of data with the
|
||||||
// with the indicated name. The name is an arbitrary
|
// indicated object (or NULL), and the indicated name.
|
||||||
// user-defined key to access the data later. This data
|
//
|
||||||
// is typically queried by objects reading themselves
|
// This is intended to provide a place for temporary
|
||||||
// from the bam file; this is intended to provide some
|
// storage for objects reading themselves from the bam
|
||||||
// context information to objects in the bam file. Set
|
// file. To use it, inherit from BamReader::AuxData and
|
||||||
// the aux data to NULL to remove it.
|
// store whatever data you like there. Then associate
|
||||||
|
// your AuxData with the object as it is being read with
|
||||||
|
// set_aux_data(). You may later set the aux data to
|
||||||
|
// NULL to remove it; or it will automatically be
|
||||||
|
// removed (and deleted) after finalize() is called for
|
||||||
|
// the object in question.
|
||||||
|
//
|
||||||
|
// If the TypedWritable pointer is NULL, the the aux
|
||||||
|
// data is stored globally for the BamReader in general.
|
||||||
|
// This pointer is available to any bam objects, and
|
||||||
|
// will not be automatically removed until the BamReader
|
||||||
|
// itself destructs.
|
||||||
|
//
|
||||||
|
// In either case, the name is just an arbitrary
|
||||||
|
// user-defined key. If there is already a data pointer
|
||||||
|
// stored for the obj/name pair, that data pointer will
|
||||||
|
// be replaced (and deleted).
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void BamReader::
|
void BamReader::
|
||||||
set_aux_data(const string &name, void *data) {
|
set_aux_data(TypedWritable *obj, const string &name, BamReader::AuxData *data) {
|
||||||
if (data == (void *)NULL) {
|
if (data == (void *)NULL) {
|
||||||
_aux_data.erase(name);
|
AuxDataTable::iterator ti = _aux_data.find(obj);
|
||||||
|
if (ti != _aux_data.end()) {
|
||||||
|
AuxDataNames &names = (*ti).second;
|
||||||
|
names.erase(name);
|
||||||
|
if (names.empty()) {
|
||||||
|
_aux_data.erase(ti);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
_aux_data[name] = data;
|
_aux_data[obj][name] = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,15 +181,19 @@ set_aux_data(const string &name, void *data) {
|
|||||||
// Access: Public
|
// Access: Public
|
||||||
// Description: Returns the pointer previously associated with the
|
// Description: Returns the pointer previously associated with the
|
||||||
// bam reader by a previous call to set_aux_data(), or
|
// bam reader by a previous call to set_aux_data(), or
|
||||||
// NULL if the data with the indicated key has not been
|
// NULL if data with the indicated key has not been set.
|
||||||
// set.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void *BamReader::
|
BamReader::AuxData *BamReader::
|
||||||
get_aux_data(const string &name) const {
|
get_aux_data(TypedWritable *obj, const string &name) const {
|
||||||
AuxData::const_iterator di = _aux_data.find(name);
|
AuxDataTable::const_iterator ti = _aux_data.find(obj);
|
||||||
if (di != _aux_data.end()) {
|
if (ti != _aux_data.end()) {
|
||||||
return (*di).second;
|
const AuxDataNames &names = (*ti).second;
|
||||||
|
AuxDataNames::const_iterator ni = names.find(name);
|
||||||
|
if (ni != names.end()) {
|
||||||
|
return (*ni).second;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,7 +301,30 @@ resolve() {
|
|||||||
all_completed = true;
|
all_completed = true;
|
||||||
any_completed_this_pass = false;
|
any_completed_this_pass = false;
|
||||||
|
|
||||||
// Walk through all the objects that still have outstanding pointers.
|
// First do the PipelineCycler objects.
|
||||||
|
CyclerPointers::iterator ci;
|
||||||
|
ci = _cycler_pointers.begin();
|
||||||
|
while (ci != _cycler_pointers.end()) {
|
||||||
|
PipelineCyclerBase *cycler = (*ci).first;
|
||||||
|
const vector_int &pointer_ids = (*ci).second;
|
||||||
|
|
||||||
|
if (resolve_cycler_pointers(cycler, pointer_ids)) {
|
||||||
|
// Now remove this cycler from the list of things that need
|
||||||
|
// completion. We have to be a bit careful when deleting things
|
||||||
|
// from the STL container while we are traversing it.
|
||||||
|
CyclerPointers::iterator old = ci;
|
||||||
|
++ci;
|
||||||
|
_cycler_pointers.erase(old);
|
||||||
|
any_completed_this_pass = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Couldn't complete this cycler yet; it'll wait for next time.
|
||||||
|
++ci;
|
||||||
|
all_completed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now do the main objects.
|
||||||
ObjectPointers::iterator oi;
|
ObjectPointers::iterator oi;
|
||||||
oi = _object_pointers.begin();
|
oi = _object_pointers.begin();
|
||||||
while (oi != _object_pointers.end()) {
|
while (oi != _object_pointers.end()) {
|
||||||
@ -320,32 +371,9 @@ resolve() {
|
|||||||
all_completed = false;
|
all_completed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (!all_completed && any_completed_this_pass);
|
} while (!all_completed && any_completed_this_pass);
|
||||||
|
|
||||||
// Also do the PipelineCycler objects. We only need to try these
|
|
||||||
// once, since they don't depend on each other.
|
|
||||||
|
|
||||||
CyclerPointers::iterator ci;
|
|
||||||
ci = _cycler_pointers.begin();
|
|
||||||
while (ci != _cycler_pointers.end()) {
|
|
||||||
PipelineCyclerBase *cycler = (*ci).first;
|
|
||||||
const vector_int &pointer_ids = (*ci).second;
|
|
||||||
|
|
||||||
if (resolve_cycler_pointers(cycler, pointer_ids)) {
|
|
||||||
// Now remove this cycler from the list of things that need
|
|
||||||
// completion. We have to be a bit careful when deleting things
|
|
||||||
// from the STL container while we are traversing it.
|
|
||||||
CyclerPointers::iterator old = ci;
|
|
||||||
++ci;
|
|
||||||
_cycler_pointers.erase(old);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Couldn't complete this cycler yet; it'll wait for next time.
|
|
||||||
++ci;
|
|
||||||
all_completed = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (all_completed) {
|
if (all_completed) {
|
||||||
finalize();
|
finalize();
|
||||||
} else {
|
} else {
|
||||||
@ -396,6 +424,12 @@ change_pointer(const TypedWritable *orig_pointer, const TypedWritable *new_point
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bam_cat.is_spam()) {
|
||||||
|
bam_cat.spam()
|
||||||
|
<< "change_pointer(" << (void *)orig_pointer << ", "
|
||||||
|
<< (void *)new_pointer << ") (" << new_pointer->get_type() << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
const vector_int &old_refs = (*ci).second;
|
const vector_int &old_refs = (*ci).second;
|
||||||
vector_int &new_refs = _created_objs_by_pointer[new_pointer];
|
vector_int &new_refs = _created_objs_by_pointer[new_pointer];
|
||||||
|
|
||||||
@ -638,10 +672,14 @@ read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler,
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void BamReader::
|
void BamReader::
|
||||||
register_finalize(TypedWritable *whom) {
|
register_finalize(TypedWritable *whom) {
|
||||||
if (whom == TypedWritable::Null) {
|
nassertv(whom != (TypedWritable *)NULL);
|
||||||
bam_cat.error() << "Can't register a null pointer to finalize!" << endl;
|
|
||||||
return;
|
if (bam_cat.is_spam()) {
|
||||||
|
bam_cat.spam()
|
||||||
|
<< "register_finalize(" << (void *)whom << ") (" << whom->get_type()
|
||||||
|
<< ")\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
_finalize_list.insert(whom);
|
_finalize_list.insert(whom);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -698,6 +736,11 @@ finalize_now(TypedWritable *whom) {
|
|||||||
Finalize::iterator fi = _finalize_list.find(whom);
|
Finalize::iterator fi = _finalize_list.find(whom);
|
||||||
if (fi != _finalize_list.end()) {
|
if (fi != _finalize_list.end()) {
|
||||||
_finalize_list.erase(fi);
|
_finalize_list.erase(fi);
|
||||||
|
if (bam_cat.is_spam()) {
|
||||||
|
bam_cat.spam()
|
||||||
|
<< "finalizing " << (void *)whom << " (" << whom->get_type()
|
||||||
|
<< ")\n";
|
||||||
|
}
|
||||||
whom->finalize(this);
|
whom->finalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -994,7 +1037,7 @@ p_read_object() {
|
|||||||
} else {
|
} else {
|
||||||
if (bam_cat.is_spam()) {
|
if (bam_cat.is_spam()) {
|
||||||
bam_cat.spam()
|
bam_cat.spam()
|
||||||
<< "Read a " << object->get_type() << "\n";
|
<< "Read a " << object->get_type() << ": " << (void *)object << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1018,12 +1061,17 @@ resolve_object_pointers(TypedWritable *object, const vector_int &pointer_ids) {
|
|||||||
// given object until we have *all* outstanding pointers for
|
// given object until we have *all* outstanding pointers for
|
||||||
// that object.
|
// that object.
|
||||||
bool is_complete = true;
|
bool is_complete = true;
|
||||||
|
|
||||||
|
// Some objects further require all of their nested objects to have
|
||||||
|
// been completed (i.e. complete_pointers has been called on each
|
||||||
|
// nested object) before they can themselves be completed.
|
||||||
|
bool require_fully_complete = object->require_fully_complete();
|
||||||
|
|
||||||
vector_typedWritable references;
|
vector_typedWritable references;
|
||||||
|
|
||||||
vector_int::const_iterator pi;
|
vector_int::const_iterator pi;
|
||||||
for (pi = pointer_ids.begin(); pi != pointer_ids.end() && is_complete; ++pi) {
|
for (pi = pointer_ids.begin(); pi != pointer_ids.end() && is_complete; ++pi) {
|
||||||
int child_id = (*pi);
|
int child_id = (*pi);
|
||||||
|
|
||||||
if (child_id == 0) {
|
if (child_id == 0) {
|
||||||
// A NULL pointer is a NULL pointer.
|
// A NULL pointer is a NULL pointer.
|
||||||
references.push_back((TypedWritable *)NULL);
|
references.push_back((TypedWritable *)NULL);
|
||||||
@ -1041,6 +1089,12 @@ resolve_object_pointers(TypedWritable *object, const vector_int &pointer_ids) {
|
|||||||
// It's been created, but the pointer might still change.
|
// It's been created, but the pointer might still change.
|
||||||
is_complete = false;
|
is_complete = false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (require_fully_complete &&
|
||||||
|
_object_pointers.find(child_id) != _object_pointers.end()) {
|
||||||
|
// It's not yet complete itself.
|
||||||
|
is_complete = false;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Yes, it's ready.
|
// Yes, it's ready.
|
||||||
references.push_back(child_obj._ptr);
|
references.push_back(child_obj._ptr);
|
||||||
@ -1048,9 +1102,18 @@ resolve_object_pointers(TypedWritable *object, const vector_int &pointer_ids) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (is_complete) {
|
if (is_complete) {
|
||||||
// Okay, here's the complete list of pointers for you!
|
// Okay, here's the complete list of pointers for you!
|
||||||
|
nassertr(references.size() == pointer_ids.size(), false);
|
||||||
|
|
||||||
|
if (bam_cat.is_spam()) {
|
||||||
|
bam_cat.spam()
|
||||||
|
<< "complete_pointers for " << (void *)object
|
||||||
|
<< " (" << object->get_type() << "), " << references.size()
|
||||||
|
<< " pointers.\n";
|
||||||
|
}
|
||||||
int num_completed = object->complete_pointers(&references[0], this);
|
int num_completed = object->complete_pointers(&references[0], this);
|
||||||
if (num_completed != (int)references.size()) {
|
if (num_completed != (int)references.size()) {
|
||||||
bam_cat.warning()
|
bam_cat.warning()
|
||||||
@ -1058,6 +1121,13 @@ resolve_object_pointers(TypedWritable *object, const vector_int &pointer_ids) {
|
|||||||
<< " of " << references.size() << " pointers.\n";
|
<< " of " << references.size() << " pointers.\n";
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (bam_cat.is_spam()) {
|
||||||
|
bam_cat.spam()
|
||||||
|
<< "not ready: complete_pointers for " << (void *)object
|
||||||
|
<< " (" << object->get_type() << ")\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -1115,6 +1185,11 @@ resolve_cycler_pointers(PipelineCyclerBase *cycler,
|
|||||||
if (is_complete) {
|
if (is_complete) {
|
||||||
// Okay, here's the complete list of pointers for you!
|
// Okay, here's the complete list of pointers for you!
|
||||||
CycleData *cdata = cycler->write(Thread::get_current_thread());
|
CycleData *cdata = cycler->write(Thread::get_current_thread());
|
||||||
|
if (bam_cat.is_spam()) {
|
||||||
|
bam_cat.spam()
|
||||||
|
<< "complete_pointers for CycleData object " << (void *)cdata
|
||||||
|
<< "\n";
|
||||||
|
}
|
||||||
int num_completed = cdata->complete_pointers(&references[0], this);
|
int num_completed = cdata->complete_pointers(&references[0], this);
|
||||||
cycler->release_write(cdata);
|
cycler->release_write(cdata);
|
||||||
if (num_completed != (int)references.size()) {
|
if (num_completed != (int)references.size()) {
|
||||||
@ -1147,8 +1222,42 @@ finalize() {
|
|||||||
TypedWritable *object = (*fi);
|
TypedWritable *object = (*fi);
|
||||||
nassertv(object != (TypedWritable *)NULL);
|
nassertv(object != (TypedWritable *)NULL);
|
||||||
_finalize_list.erase(fi);
|
_finalize_list.erase(fi);
|
||||||
|
if (bam_cat.is_spam()) {
|
||||||
|
bam_cat.spam()
|
||||||
|
<< "finalizing " << (void *)object << " (" << object->get_type()
|
||||||
|
<< ")\n";
|
||||||
|
}
|
||||||
object->finalize(this);
|
object->finalize(this);
|
||||||
|
_aux_data.erase(object);
|
||||||
fi = _finalize_list.begin();
|
fi = _finalize_list.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now clear the aux data of all objects, except the NULL object.
|
||||||
|
if (!_aux_data.empty()) {
|
||||||
|
AuxDataTable::iterator ti = _aux_data.find((TypedWritable *)NULL);
|
||||||
|
|
||||||
|
if (ti != _aux_data.end()) {
|
||||||
|
if (_aux_data.size() > 1) {
|
||||||
|
// Move the NULL data to the new table; remove the rest.
|
||||||
|
AuxDataTable new_aux_data;
|
||||||
|
AuxDataTable::iterator nti =
|
||||||
|
new_aux_data.insert(AuxDataTable::value_type(NULL, AuxDataNames())).first;
|
||||||
|
(*nti).second.swap((*ti).second);
|
||||||
|
_aux_data.swap(new_aux_data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// There's no NULL data; clear the whole table.
|
||||||
|
_aux_data.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: BamReader::AuxData::Destructor
|
||||||
|
// Access: Public, Virtual
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
BamReader::AuxData::
|
||||||
|
~AuxData() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -98,8 +98,10 @@ public:
|
|||||||
|
|
||||||
bool init();
|
bool init();
|
||||||
|
|
||||||
void set_aux_data(const string &name, void *data);
|
class AuxData;
|
||||||
void *get_aux_data(const string &name) const;
|
void set_aux_data(TypedWritable *obj, const string &name, AuxData *data);
|
||||||
|
AuxData *get_aux_data(TypedWritable *obj, const string &name) const;
|
||||||
|
|
||||||
INLINE const Filename &get_filename() const;
|
INLINE const Filename &get_filename() const;
|
||||||
|
|
||||||
TypedWritable *read_object();
|
TypedWritable *read_object();
|
||||||
@ -115,10 +117,6 @@ public:
|
|||||||
INLINE int get_current_major_ver() const;
|
INLINE int get_current_major_ver() const;
|
||||||
INLINE int get_current_minor_ver() const;
|
INLINE int get_current_minor_ver() const;
|
||||||
|
|
||||||
// This special TypeHandle is written to the bam file to indicate an
|
|
||||||
// object id is no longer needed.
|
|
||||||
static TypeHandle _remove_flag;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Functions to support classes that read themselves from the Bam.
|
// Functions to support classes that read themselves from the Bam.
|
||||||
|
|
||||||
@ -161,6 +159,20 @@ private:
|
|||||||
|
|
||||||
INLINE bool get_datagram(Datagram &datagram);
|
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.
|
||||||
|
class AuxData : public ReferenceCount {
|
||||||
|
public:
|
||||||
|
INLINE AuxData();
|
||||||
|
virtual ~AuxData();
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static WritableFactory *_factory;
|
static WritableFactory *_factory;
|
||||||
|
|
||||||
@ -234,8 +246,9 @@ private:
|
|||||||
static NewTypes _new_types;
|
static NewTypes _new_types;
|
||||||
|
|
||||||
// This is used in support of set_aux_data() and get_aux_data().
|
// This is used in support of set_aux_data() and get_aux_data().
|
||||||
typedef phash_map<string, void *, string_hash> AuxData;
|
typedef pmap<string, PT(AuxData)> AuxDataNames;
|
||||||
AuxData _aux_data;
|
typedef phash_map<TypedWritable *, AuxDataNames, pointer_hash> AuxDataTable;
|
||||||
|
AuxDataTable _aux_data;
|
||||||
|
|
||||||
int _file_major, _file_minor;
|
int _file_major, _file_minor;
|
||||||
BamEndian _file_endian;
|
BamEndian _file_endian;
|
||||||
|
@ -86,6 +86,20 @@ complete_pointers(TypedWritable **, BamReader *) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TypedWritable::require_fully_complete
|
||||||
|
// Access: Public, Virtual
|
||||||
|
// Description: Some objects require all of their nested pointers to
|
||||||
|
// have been completed before the objects themselves can
|
||||||
|
// be completed. If this is the case, override this
|
||||||
|
// method to return true, and be careful with circular
|
||||||
|
// references (which would make the object unreadable
|
||||||
|
// from a bam file).
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool TypedWritable::
|
||||||
|
require_fully_complete() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: TypedWritable::finalize
|
// Function: TypedWritable::finalize
|
||||||
|
@ -50,6 +50,7 @@ public:
|
|||||||
virtual void write_datagram(BamWriter *, Datagram &);
|
virtual void write_datagram(BamWriter *, Datagram &);
|
||||||
|
|
||||||
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager);
|
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager);
|
||||||
|
virtual bool require_fully_complete() const;
|
||||||
|
|
||||||
virtual void finalize(BamReader *manager);
|
virtual void finalize(BamReader *manager);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user