mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
bam: Fix circular reference with ClipPlaneAttrib
What's being addressed here is the circumstance where an ancestor of a PlaneNode has a ClipPlaneAttrib that references said PlaneNode. The code here is just being copied out of LightAttrib, which has the exact same mode of operation (it nominates a sorted list of on/off NodePaths) and a compatible structure. LightAttrib has had this problem in the past, so using the same solution makes sense.
This commit is contained in:
parent
74bb2fef2e
commit
fd6eebb7fe
@ -900,12 +900,52 @@ 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();
|
|
||||||
|
|
||||||
if (manager->get_file_minor_ver() >= 40) {
|
if (manager->get_file_minor_ver() >= 40) {
|
||||||
for (size_t i = 0; i < _off_planes.size(); ++i) {
|
for (size_t i = 0; i < _off_planes.size(); ++i) {
|
||||||
pi += _off_planes[i].complete_pointers(p_list + pi, manager);
|
pi += _off_planes[i].complete_pointers(p_list + pi, manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < _on_planes.size(); ++i) {
|
||||||
|
pi += _on_planes[i].complete_pointers(p_list + pi, manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
BamAuxData *aux = (BamAuxData *)manager->get_aux_data(this, "planes");
|
||||||
|
nassertr(aux != NULL, pi);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
aux->_off_list.reserve(aux->_num_off_planes);
|
||||||
|
for (i = 0; i < aux->_num_off_planes; ++i) {
|
||||||
|
PandaNode *node;
|
||||||
|
DCAST_INTO_R(node, p_list[pi++], pi);
|
||||||
|
aux->_off_list.push_back(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
aux->_on_list.reserve(aux->_num_on_planes);
|
||||||
|
for (i = 0; i < aux->_num_on_planes; ++i) {
|
||||||
|
PandaNode *node;
|
||||||
|
DCAST_INTO_R(node, p_list[pi++], pi);
|
||||||
|
aux->_on_list.push_back(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pi;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 ClipPlaneAttrib::
|
||||||
|
finalize(BamReader *manager) {
|
||||||
|
if (manager->get_file_minor_ver() >= 40) {
|
||||||
|
AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr();
|
||||||
|
|
||||||
|
// Check if any of the nodes we loaded are mentioned in the
|
||||||
|
// AttribNodeRegistry. If so, replace them.
|
||||||
|
for (size_t i = 0; i < _off_planes.size(); ++i) {
|
||||||
int n = areg->find_node(_off_planes[i]);
|
int n = areg->find_node(_off_planes[i]);
|
||||||
if (n != -1) {
|
if (n != -1) {
|
||||||
// If it's in the registry, replace it.
|
// If it's in the registry, replace it.
|
||||||
@ -914,8 +954,6 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < _on_planes.size(); ++i) {
|
for (size_t i = 0; i < _on_planes.size(); ++i) {
|
||||||
pi += _on_planes[i].complete_pointers(p_list + pi, manager);
|
|
||||||
|
|
||||||
int n = areg->find_node(_on_planes[i]);
|
int n = areg->find_node(_on_planes[i]);
|
||||||
if (n != -1) {
|
if (n != -1) {
|
||||||
// If it's in the registry, replace it.
|
// If it's in the registry, replace it.
|
||||||
@ -924,53 +962,46 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Planes::iterator ci = _off_planes.begin();
|
// Now it's safe to convert our saved PandaNodes into NodePaths.
|
||||||
while (ci != _off_planes.end()) {
|
BamAuxData *aux = (BamAuxData *)manager->get_aux_data(this, "planes");
|
||||||
PandaNode *node;
|
nassertv(aux != NULL);
|
||||||
DCAST_INTO_R(node, p_list[pi++], pi);
|
nassertv(aux->_num_off_planes == (int)aux->_off_list.size());
|
||||||
|
nassertv(aux->_num_on_planes == (int)aux->_on_list.size());
|
||||||
|
|
||||||
// We go through some effort to look up the node in the registry without
|
AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr();
|
||||||
// creating a NodePath around it first (which would up, and then down,
|
|
||||||
// the reference count, possibly deleting the node).
|
_off_planes.reserve(aux->_off_list.size());
|
||||||
int ni = areg->find_node(node->get_type(), node->get_name());
|
NodeList::iterator ni;
|
||||||
if (ni != -1) {
|
for (ni = aux->_off_list.begin(); ni != aux->_off_list.end(); ++ni) {
|
||||||
(*ci) = areg->get_node(ni);
|
PandaNode *node = (*ni);
|
||||||
|
int n = areg->find_node(node->get_type(), node->get_name());
|
||||||
|
if (n != -1) {
|
||||||
|
// If it's in the registry, add that NodePath.
|
||||||
|
_off_planes.push_back(areg->get_node(n));
|
||||||
} else {
|
} else {
|
||||||
(*ci) = NodePath(node);
|
// Otherwise, add any arbitrary NodePath. Complain if it's ambiguous.
|
||||||
|
_off_planes.push_back(NodePath(node));
|
||||||
}
|
}
|
||||||
++ci;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ci = _on_planes.begin();
|
_on_planes.reserve(aux->_on_list.size());
|
||||||
while (ci != _on_planes.end()) {
|
for (ni = aux->_on_list.begin(); ni != aux->_on_list.end(); ++ni) {
|
||||||
PandaNode *node;
|
PandaNode *node = (*ni);
|
||||||
DCAST_INTO_R(node, p_list[pi++], pi);
|
int n = areg->find_node(node->get_type(), node->get_name());
|
||||||
|
if (n != -1) {
|
||||||
int ni = areg->find_node(node->get_type(), node->get_name());
|
// If it's in the registry, add that NodePath.
|
||||||
if (ni != -1) {
|
_on_planes.push_back(areg->get_node(n));
|
||||||
(*ci) = areg->get_node(ni);
|
node = _on_planes.back().node();
|
||||||
} else {
|
} else {
|
||||||
(*ci) = NodePath(node);
|
// Otherwise, add any arbitrary NodePath. Complain if it's ambiguous.
|
||||||
|
_on_planes.push_back(NodePath(node));
|
||||||
}
|
}
|
||||||
++ci;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now that the NodePaths have been filled in, we can sort the list.
|
||||||
_off_planes.sort();
|
_off_planes.sort();
|
||||||
_on_planes.sort();
|
_on_planes.sort();
|
||||||
|
|
||||||
return pi;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -987,6 +1018,8 @@ make_from_bam(const FactoryParams ¶ms) {
|
|||||||
parse_params(params, scan, manager);
|
parse_params(params, scan, manager);
|
||||||
attrib->fillin(scan, manager);
|
attrib->fillin(scan, manager);
|
||||||
|
|
||||||
|
manager->register_finalize(attrib);
|
||||||
|
|
||||||
return attrib;
|
return attrib;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1000,26 +1033,24 @@ fillin(DatagramIterator &scan, BamReader *manager) {
|
|||||||
|
|
||||||
_off_all_planes = scan.get_bool();
|
_off_all_planes = scan.get_bool();
|
||||||
|
|
||||||
int num_off_planes = scan.get_uint16();
|
|
||||||
|
|
||||||
// Push back an empty NodePath for each off Plane for now, until we get the
|
|
||||||
// actual list of pointers later in complete_pointers().
|
|
||||||
_off_planes.resize(num_off_planes);
|
|
||||||
if (manager->get_file_minor_ver() >= 40) {
|
if (manager->get_file_minor_ver() >= 40) {
|
||||||
for (int i = 0; i < num_off_planes; i++) {
|
_off_planes.resize(scan.get_uint16());
|
||||||
|
for (size_t i = 0; i < _off_planes.size(); ++i) {
|
||||||
_off_planes[i].fillin(scan, manager);
|
_off_planes[i].fillin(scan, manager);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
manager->read_pointers(scan, num_off_planes);
|
|
||||||
}
|
|
||||||
|
|
||||||
int num_on_planes = scan.get_uint16();
|
_on_planes.resize(scan.get_uint16());
|
||||||
_on_planes.resize(num_on_planes);
|
for (size_t i = 0; i < _on_planes.size(); ++i) {
|
||||||
if (manager->get_file_minor_ver() >= 40) {
|
|
||||||
for (int i = 0; i < num_on_planes; i++) {
|
|
||||||
_on_planes[i].fillin(scan, manager);
|
_on_planes[i].fillin(scan, manager);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
manager->read_pointers(scan, num_on_planes);
|
BamAuxData *aux = new BamAuxData;
|
||||||
|
manager->set_aux_data(this, "planes", aux);
|
||||||
|
|
||||||
|
aux->_num_off_planes = scan.get_uint16();
|
||||||
|
manager->read_pointers(scan, aux->_num_off_planes);
|
||||||
|
|
||||||
|
aux->_num_on_planes = scan.get_uint16();
|
||||||
|
manager->read_pointers(scan, aux->_num_on_planes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,11 +125,26 @@ PUBLISHED:
|
|||||||
}
|
}
|
||||||
MAKE_PROPERTY(class_slot, get_class_slot);
|
MAKE_PROPERTY(class_slot, get_class_slot);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// This data is only needed when reading from a bam file.
|
||||||
|
typedef pvector<PT(PandaNode) > NodeList;
|
||||||
|
class BamAuxData : public BamReader::AuxData {
|
||||||
|
public:
|
||||||
|
// We hold a pointer to each of the PandaNodes on the on_list and
|
||||||
|
// off_list. We will later convert these to NodePaths in
|
||||||
|
// finalize().
|
||||||
|
int _num_off_planes;
|
||||||
|
int _num_on_planes;
|
||||||
|
NodeList _off_list;
|
||||||
|
NodeList _on_list;
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
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;
|
|
||||||
|
virtual void finalize(BamReader *manager);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static TypedWritable *make_from_bam(const FactoryParams ¶ms);
|
static TypedWritable *make_from_bam(const FactoryParams ¶ms);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user