Skip to content

Commit fd6eebb

Browse files
committed
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.
1 parent 74bb2fe commit fd6eebb

File tree

2 files changed

+100
-54
lines changed

2 files changed

+100
-54
lines changed

panda/src/pgraph/clipPlaneAttrib.cxx

Lines changed: 84 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -900,12 +900,52 @@ write_datagram(BamWriter *manager, Datagram &dg) {
900900
int ClipPlaneAttrib::
901901
complete_pointers(TypedWritable **p_list, BamReader *manager) {
902902
int pi = RenderAttrib::complete_pointers(p_list, manager);
903-
AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr();
904903

905904
if (manager->get_file_minor_ver() >= 40) {
906905
for (size_t i = 0; i < _off_planes.size(); ++i) {
907906
pi += _off_planes[i].complete_pointers(p_list + pi, manager);
907+
}
908+
909+
for (size_t i = 0; i < _on_planes.size(); ++i) {
910+
pi += _on_planes[i].complete_pointers(p_list + pi, manager);
911+
}
912+
913+
} else {
914+
BamAuxData *aux = (BamAuxData *)manager->get_aux_data(this, "planes");
915+
nassertr(aux != NULL, pi);
908916

917+
int i;
918+
aux->_off_list.reserve(aux->_num_off_planes);
919+
for (i = 0; i < aux->_num_off_planes; ++i) {
920+
PandaNode *node;
921+
DCAST_INTO_R(node, p_list[pi++], pi);
922+
aux->_off_list.push_back(node);
923+
}
924+
925+
aux->_on_list.reserve(aux->_num_on_planes);
926+
for (i = 0; i < aux->_num_on_planes; ++i) {
927+
PandaNode *node;
928+
DCAST_INTO_R(node, p_list[pi++], pi);
929+
aux->_on_list.push_back(node);
930+
}
931+
}
932+
933+
return pi;
934+
}
935+
936+
/**
937+
* Called by the BamReader to perform any final actions needed for setting up
938+
* the object after all objects have been read and all pointers have been
939+
* completed.
940+
*/
941+
void ClipPlaneAttrib::
942+
finalize(BamReader *manager) {
943+
if (manager->get_file_minor_ver() >= 40) {
944+
AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr();
945+
946+
// Check if any of the nodes we loaded are mentioned in the
947+
// AttribNodeRegistry. If so, replace them.
948+
for (size_t i = 0; i < _off_planes.size(); ++i) {
909949
int n = areg->find_node(_off_planes[i]);
910950
if (n != -1) {
911951
// If it's in the registry, replace it.
@@ -914,8 +954,6 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
914954
}
915955

916956
for (size_t i = 0; i < _on_planes.size(); ++i) {
917-
pi += _on_planes[i].complete_pointers(p_list + pi, manager);
918-
919957
int n = areg->find_node(_on_planes[i]);
920958
if (n != -1) {
921959
// If it's in the registry, replace it.
@@ -924,53 +962,46 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
924962
}
925963

926964
} else {
927-
Planes::iterator ci = _off_planes.begin();
928-
while (ci != _off_planes.end()) {
929-
PandaNode *node;
930-
DCAST_INTO_R(node, p_list[pi++], pi);
931-
932-
// We go through some effort to look up the node in the registry without
933-
// creating a NodePath around it first (which would up, and then down,
934-
// the reference count, possibly deleting the node).
935-
int ni = areg->find_node(node->get_type(), node->get_name());
936-
if (ni != -1) {
937-
(*ci) = areg->get_node(ni);
965+
// Now it's safe to convert our saved PandaNodes into NodePaths.
966+
BamAuxData *aux = (BamAuxData *)manager->get_aux_data(this, "planes");
967+
nassertv(aux != NULL);
968+
nassertv(aux->_num_off_planes == (int)aux->_off_list.size());
969+
nassertv(aux->_num_on_planes == (int)aux->_on_list.size());
970+
971+
AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr();
972+
973+
_off_planes.reserve(aux->_off_list.size());
974+
NodeList::iterator ni;
975+
for (ni = aux->_off_list.begin(); ni != aux->_off_list.end(); ++ni) {
976+
PandaNode *node = (*ni);
977+
int n = areg->find_node(node->get_type(), node->get_name());
978+
if (n != -1) {
979+
// If it's in the registry, add that NodePath.
980+
_off_planes.push_back(areg->get_node(n));
938981
} else {
939-
(*ci) = NodePath(node);
982+
// Otherwise, add any arbitrary NodePath. Complain if it's ambiguous.
983+
_off_planes.push_back(NodePath(node));
940984
}
941-
++ci;
942985
}
943986

944-
ci = _on_planes.begin();
945-
while (ci != _on_planes.end()) {
946-
PandaNode *node;
947-
DCAST_INTO_R(node, p_list[pi++], pi);
948-
949-
int ni = areg->find_node(node->get_type(), node->get_name());
950-
if (ni != -1) {
951-
(*ci) = areg->get_node(ni);
987+
_on_planes.reserve(aux->_on_list.size());
988+
for (ni = aux->_on_list.begin(); ni != aux->_on_list.end(); ++ni) {
989+
PandaNode *node = (*ni);
990+
int n = areg->find_node(node->get_type(), node->get_name());
991+
if (n != -1) {
992+
// If it's in the registry, add that NodePath.
993+
_on_planes.push_back(areg->get_node(n));
994+
node = _on_planes.back().node();
952995
} else {
953-
(*ci) = NodePath(node);
996+
// Otherwise, add any arbitrary NodePath. Complain if it's ambiguous.
997+
_on_planes.push_back(NodePath(node));
954998
}
955-
++ci;
956999
}
9571000
}
9581001

1002+
// Now that the NodePaths have been filled in, we can sort the list.
9591003
_off_planes.sort();
9601004
_on_planes.sort();
961-
962-
return pi;
963-
}
964-
965-
/**
966-
* Some objects require all of their nested pointers to have been completed
967-
* before the objects themselves can be completed. If this is the case,
968-
* override this method to return true, and be careful with circular
969-
* references (which would make the object unreadable from a bam file).
970-
*/
971-
bool ClipPlaneAttrib::
972-
require_fully_complete() const {
973-
return true;
9741005
}
9751006

9761007
/**
@@ -987,6 +1018,8 @@ make_from_bam(const FactoryParams &params) {
9871018
parse_params(params, scan, manager);
9881019
attrib->fillin(scan, manager);
9891020

1021+
manager->register_finalize(attrib);
1022+
9901023
return attrib;
9911024
}
9921025

@@ -1000,26 +1033,24 @@ fillin(DatagramIterator &scan, BamReader *manager) {
10001033

10011034
_off_all_planes = scan.get_bool();
10021035

1003-
int num_off_planes = scan.get_uint16();
1004-
1005-
// Push back an empty NodePath for each off Plane for now, until we get the
1006-
// actual list of pointers later in complete_pointers().
1007-
_off_planes.resize(num_off_planes);
10081036
if (manager->get_file_minor_ver() >= 40) {
1009-
for (int i = 0; i < num_off_planes; i++) {
1037+
_off_planes.resize(scan.get_uint16());
1038+
for (size_t i = 0; i < _off_planes.size(); ++i) {
10101039
_off_planes[i].fillin(scan, manager);
10111040
}
1012-
} else {
1013-
manager->read_pointers(scan, num_off_planes);
1014-
}
10151041

1016-
int num_on_planes = scan.get_uint16();
1017-
_on_planes.resize(num_on_planes);
1018-
if (manager->get_file_minor_ver() >= 40) {
1019-
for (int i = 0; i < num_on_planes; i++) {
1042+
_on_planes.resize(scan.get_uint16());
1043+
for (size_t i = 0; i < _on_planes.size(); ++i) {
10201044
_on_planes[i].fillin(scan, manager);
10211045
}
10221046
} else {
1023-
manager->read_pointers(scan, num_on_planes);
1047+
BamAuxData *aux = new BamAuxData;
1048+
manager->set_aux_data(this, "planes", aux);
1049+
1050+
aux->_num_off_planes = scan.get_uint16();
1051+
manager->read_pointers(scan, aux->_num_off_planes);
1052+
1053+
aux->_num_on_planes = scan.get_uint16();
1054+
manager->read_pointers(scan, aux->_num_on_planes);
10241055
}
10251056
}

panda/src/pgraph/clipPlaneAttrib.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,26 @@ class EXPCL_PANDA_PGRAPH ClipPlaneAttrib : public RenderAttrib {
125125
}
126126
MAKE_PROPERTY(class_slot, get_class_slot);
127127

128+
public:
129+
// This data is only needed when reading from a bam file.
130+
typedef pvector<PT(PandaNode) > NodeList;
131+
class BamAuxData : public BamReader::AuxData {
132+
public:
133+
// We hold a pointer to each of the PandaNodes on the on_list and
134+
// off_list. We will later convert these to NodePaths in
135+
// finalize().
136+
int _num_off_planes;
137+
int _num_on_planes;
138+
NodeList _off_list;
139+
NodeList _on_list;
140+
};
141+
128142
public:
129143
static void register_with_read_factory();
130144
virtual void write_datagram(BamWriter *manager, Datagram &dg);
131145
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
132-
virtual bool require_fully_complete() const;
146+
147+
virtual void finalize(BamReader *manager);
133148

134149
protected:
135150
static TypedWritable *make_from_bam(const FactoryParams &params);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy