diff --git a/panda/src/express/ordered_vector.I b/panda/src/express/ordered_vector.I index ec0f23bfb6..6a5350f079 100644 --- a/panda/src/express/ordered_vector.I +++ b/panda/src/express/ordered_vector.I @@ -694,6 +694,34 @@ pop_back() { _vector.pop_back(); } +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::resize +// Access: Public +// Description: Resizes the vector to contain n elements. This +// should not be used except to populate the vector +// for the first time. +//////////////////////////////////////////////////////////////////// +template +INLINE void ordered_vector:: +resize(SIZE_TYPE n) { + TAU_PROFILE("ordered_vector::resize()", " ", TAU_USER); + _vector.resize(n); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::resize +// Access: Public +// Description: Resizes the vector to contain n elements. This +// should not be used except to populate the vector +// for the first time. +//////////////////////////////////////////////////////////////////// +template +INLINE void ordered_vector:: +resize(SIZE_TYPE n, const VALUE_TYPE &value) { + TAU_PROFILE("ordered_vector::resize()", " ", TAU_USER); + _vector.resize(n, value); +} + //////////////////////////////////////////////////////////////////// // Function: ordered_vector::nci // Access: Private diff --git a/panda/src/express/ordered_vector.h b/panda/src/express/ordered_vector.h index 705212b98d..2eebdcfa23 100644 --- a/panda/src/express/ordered_vector.h +++ b/panda/src/express/ordered_vector.h @@ -219,6 +219,8 @@ public: INLINE void push_back(const VALUE_TYPE &key); INLINE void pop_back(); + INLINE void resize(SIZE_TYPE n); + INLINE void resize(SIZE_TYPE n, const VALUE_TYPE &value); private: INLINE ITERATOR nci(CONST_ITERATOR i); diff --git a/panda/src/gobj/texturePool.cxx b/panda/src/gobj/texturePool.cxx index 4377767089..ae9cf1bfd2 100644 --- a/panda/src/gobj/texturePool.cxx +++ b/panda/src/gobj/texturePool.cxx @@ -341,7 +341,7 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels, if (store_record && tex->is_cacheable()) { // Store the on-disk cache record for next time. - record->set_data(tex, tex); + record->set_data(tex); cache->store(record); } @@ -473,7 +473,7 @@ ns_load_texture(const Filename &orig_filename, if (store_record && tex->is_cacheable()) { // Store the on-disk cache record for next time. - record->set_data(tex, tex); + record->set_data(tex); cache->store(record); } @@ -585,7 +585,7 @@ ns_load_3d_texture(const Filename &filename_pattern, if (store_record && tex->is_cacheable()) { // Store the on-disk cache record for next time. - record->set_data(tex, tex); + record->set_data(tex); cache->store(record); } @@ -691,7 +691,7 @@ ns_load_2d_texture_array(const Filename &filename_pattern, if (store_record && tex->is_cacheable()) { // Store the on-disk cache record for next time. - record->set_data(tex, tex); + record->set_data(tex); cache->store(record); } @@ -790,7 +790,7 @@ ns_load_cube_map(const Filename &filename_pattern, bool read_mipmaps, if (store_record && tex->is_cacheable()) { // Store the on-disk cache record for next time. - record->set_data(tex, tex); + record->set_data(tex); cache->store(record); } @@ -1166,7 +1166,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, tex); + record->set_data(tex); cache->store(record); compressed_cache_record = true; } diff --git a/panda/src/pgraph/clipPlaneAttrib.cxx b/panda/src/pgraph/clipPlaneAttrib.cxx index b07052125e..74a7d31bf7 100644 --- a/panda/src/pgraph/clipPlaneAttrib.cxx +++ b/panda/src/pgraph/clipPlaneAttrib.cxx @@ -960,12 +960,7 @@ write_datagram(BamWriter *manager, Datagram &dg) { // write the off planes pointers if any Planes::const_iterator fi; for (fi = _off_planes.begin(); fi != _off_planes.end(); ++fi) { - NodePath plane = (*fi); - - // 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()); + (*fi).write_datagram(manager, dg); } // write the number of on planes @@ -973,8 +968,7 @@ write_datagram(BamWriter *manager, Datagram &dg) { // write the on planes pointers if any Planes::const_iterator nti; for (nti = _on_planes.begin(); nti != _on_planes.end(); ++nti) { - NodePath plane = (*nti); - manager->write_pointer(dg, plane.node()); + (*nti).write_datagram(manager, dg); } } @@ -990,38 +984,62 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) { int pi = RenderAttrib::complete_pointers(p_list, manager); AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr(); - Planes::iterator ci = _off_planes.begin(); - while (ci != _off_planes.end()) { - PandaNode *node; - DCAST_INTO_R(node, p_list[pi++], pi); - - // We go through some effort to look up the node in the registry - // without creating a NodePath around it first (which would up, - // and then down, the reference count, possibly deleting the - // node). - int ni = areg->find_node(node->get_type(), node->get_name()); - if (ni != -1) { - (*ci) = areg->get_node(ni); - } else { - (*ci) = NodePath(node); + if (manager->get_file_minor_ver() >= 40) { + for (int i = 0; i < _off_planes.size(); ++i) { + pi += _off_planes[i].complete_pointers(p_list + pi, manager); + + int n = areg->find_node(_off_planes[i]); + if (n != -1) { + // If it's in the registry, replace it. + _off_planes[i] = areg->get_node(n); + } + } + + for (int 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]); + if (n != -1) { + // If it's in the registry, replace it. + _on_planes[i] = areg->get_node(n); + } + } + + } else { + Planes::iterator ci = _off_planes.begin(); + while (ci != _off_planes.end()) { + PandaNode *node; + DCAST_INTO_R(node, p_list[pi++], pi); + + // We go through some effort to look up the node in the registry + // without creating a NodePath around it first (which would up, + // and then down, the reference count, possibly deleting the + // node). + int ni = areg->find_node(node->get_type(), node->get_name()); + if (ni != -1) { + (*ci) = areg->get_node(ni); + } else { + (*ci) = NodePath(node); + } + ++ci; + } + + ci = _on_planes.begin(); + while (ci != _on_planes.end()) { + PandaNode *node; + DCAST_INTO_R(node, p_list[pi++], pi); + + int ni = areg->find_node(node->get_type(), node->get_name()); + if (ni != -1) { + (*ci) = areg->get_node(ni); + } else { + (*ci) = NodePath(node); + } + ++ci; } - ++ci; } + _off_planes.sort(); - - ci = _on_planes.begin(); - while (ci != _on_planes.end()) { - PandaNode *node; - DCAST_INTO_R(node, p_list[pi++], pi); - - int ni = areg->find_node(node->get_type(), node->get_name()); - if (ni != -1) { - (*ci) = areg->get_node(ni); - } else { - (*ci) = NodePath(node); - } - ++ci; - } _on_planes.sort(); return pi; @@ -1073,31 +1091,28 @@ void ClipPlaneAttrib:: fillin(DatagramIterator &scan, BamReader *manager) { RenderAttrib::fillin(scan, manager); - // We cheat a little bit here. In the middle of bam version 4.10, - // we completely redefined the bam storage definition for - // ClipPlaneAttribs, without bothering to up the bam version or even to - // attempt to read the old definition. We get away with this, - // knowing that the egg loader doesn't create ClipPlaneAttribs, and - // hence no old bam files have the old definition for ClipPlaneAttrib - // within them. - _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.reserve(num_off_planes); - int i; - for (i = 0; i < num_off_planes; i++) { - manager->read_pointer(scan); - _off_planes.push_back(NodePath()); + _off_planes.resize(num_off_planes); + if (manager->get_file_minor_ver() >= 40) { + for (int i = 0; i < num_off_planes; i++) { + _off_planes[i].fillin(scan, manager); + } + } else { + manager->read_pointers(scan, num_off_planes); } - + int num_on_planes = scan.get_uint16(); - _on_planes.reserve(num_on_planes); - for (i = 0; i < num_on_planes; i++) { - manager->read_pointer(scan); - _on_planes.push_back(NodePath()); + _on_planes.resize(num_on_planes); + if (manager->get_file_minor_ver() >= 40) { + for (int i = 0; i < num_on_planes; i++) { + manager->read_pointer(scan); + } + } else { + manager->read_pointers(scan, num_on_planes); } } diff --git a/panda/src/pgraph/lightAttrib.cxx b/panda/src/pgraph/lightAttrib.cxx index c063746824..59a83e10cb 100644 --- a/panda/src/pgraph/lightAttrib.cxx +++ b/panda/src/pgraph/lightAttrib.cxx @@ -990,12 +990,7 @@ write_datagram(BamWriter *manager, Datagram &dg) { // write the off lights pointers if any Lights::const_iterator fi; for (fi = _off_lights.begin(); fi != _off_lights.end(); ++fi) { - NodePath light = (*fi); - - // 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()); + (*fi).write_datagram(manager, dg); } // write the number of on lights @@ -1003,8 +998,7 @@ write_datagram(BamWriter *manager, Datagram &dg) { // write the on lights pointers if any Lights::const_iterator nti; for (nti = _on_lights.begin(); nti != _on_lights.end(); ++nti) { - NodePath light = (*nti); - manager->write_pointer(dg, light.node()); + (*nti).write_datagram(manager, dg); } } @@ -1019,22 +1013,33 @@ int LightAttrib:: complete_pointers(TypedWritable **p_list, BamReader *manager) { int pi = RenderAttrib::complete_pointers(p_list, manager); - BamAuxData *aux = (BamAuxData *)manager->get_aux_data(this, "lights"); - nassertr(aux != NULL, pi); + if (manager->get_file_minor_ver() >= 40) { + for (int i = 0; i < _off_lights.size(); ++i) { + pi += _off_lights[i].complete_pointers(p_list + pi, manager); + } - int i; - aux->_off_list.reserve(aux->_num_off_lights); - for (i = 0; i < aux->_num_off_lights; ++i) { - PandaNode *node; - DCAST_INTO_R(node, p_list[pi++], pi); - aux->_off_list.push_back(node); - } + for (int i = 0; i < _on_lights.size(); ++i) { + pi += _on_lights[i].complete_pointers(p_list + pi, manager); + } - aux->_on_list.reserve(aux->_num_on_lights); - for (i = 0; i < aux->_num_on_lights; ++i) { - PandaNode *node; - DCAST_INTO_R(node, p_list[pi++], pi); - aux->_on_list.push_back(node); + } else { + BamAuxData *aux = (BamAuxData *)manager->get_aux_data(this, "lights"); + nassertr(aux != NULL, pi); + + int i; + aux->_off_list.reserve(aux->_num_off_lights); + for (i = 0; i < aux->_num_off_lights; ++i) { + PandaNode *node; + DCAST_INTO_R(node, p_list[pi++], pi); + aux->_off_list.push_back(node); + } + + aux->_on_list.reserve(aux->_num_on_lights); + for (i = 0; i < aux->_num_on_lights; ++i) { + PandaNode *node; + DCAST_INTO_R(node, p_list[pi++], pi); + aux->_on_list.push_back(node); + } } return pi; @@ -1049,43 +1054,68 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) { //////////////////////////////////////////////////////////////////// void LightAttrib:: finalize(BamReader *manager) { - // Now it's safe to convert our saved PandaNodes into NodePaths. - BamAuxData *aux = (BamAuxData *)manager->get_aux_data(this, "lights"); - nassertv(aux != NULL); - nassertv(aux->_num_off_lights == (int)aux->_off_list.size()); - nassertv(aux->_num_on_lights == (int)aux->_on_list.size()); + if (manager->get_file_minor_ver() >= 40) { + AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr(); - AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr(); + // Check if any of the nodes we loaded are mentioned in the + // AttribNodeRegistry. If so, replace them. + for (int i = 0; i < _off_lights.size(); ++i) { + int n = areg->find_node(_off_lights[i]); + if (n != -1) { + // If it's in the registry, replace it. + _off_lights[i] = areg->get_node(n); + } + } - _off_lights.reserve(aux->_off_list.size()); - NodeList::iterator ni; - for (ni = aux->_off_list.begin(); ni != aux->_off_list.end(); ++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_lights.push_back(areg->get_node(n)); - } else { - // Otherwise, add any arbitrary NodePath. Complain if it's - // ambiguous. - _off_lights.push_back(NodePath(node)); + for (int i = 0; i < _on_lights.size(); ++i) { + int n = areg->find_node(_on_lights[i]); + if (n != -1) { + // If it's in the registry, replace it. + _on_lights[i] = areg->get_node(n); + } + } + + } else { + // Now it's safe to convert our saved PandaNodes into NodePaths. + BamAuxData *aux = (BamAuxData *)manager->get_aux_data(this, "lights"); + nassertv(aux != NULL); + nassertv(aux->_num_off_lights == (int)aux->_off_list.size()); + nassertv(aux->_num_on_lights == (int)aux->_on_list.size()); + + AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr(); + + _off_lights.reserve(aux->_off_list.size()); + NodeList::iterator ni; + for (ni = aux->_off_list.begin(); ni != aux->_off_list.end(); ++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_lights.push_back(areg->get_node(n)); + } else { + // Otherwise, add any arbitrary NodePath. Complain if it's + // ambiguous. + _off_lights.push_back(NodePath(node)); + } + } + + _on_lights.reserve(aux->_on_list.size()); + for (ni = aux->_on_list.begin(); ni != aux->_on_list.end(); ++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. + _on_lights.push_back(areg->get_node(n)); + } else { + // Otherwise, add any arbitrary NodePath. Complain if it's + // ambiguous. + _on_lights.push_back(NodePath(node)); + } } } + + // Now that the NodePaths have been filled in, we can sort the list. _off_lights.sort(); - - _on_lights.reserve(aux->_on_list.size()); - for (ni = aux->_on_list.begin(); ni != aux->_on_list.end(); ++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. - _on_lights.push_back(areg->get_node(n)); - } else { - // Otherwise, add any arbitrary NodePath. Complain if it's - // ambiguous. - _on_lights.push_back(NodePath(node)); - } - } _on_lights.sort(); } @@ -1124,12 +1154,24 @@ fillin(DatagramIterator &scan, BamReader *manager) { _off_all_lights = scan.get_bool(); - BamAuxData *aux = new BamAuxData; - manager->set_aux_data(this, "lights", aux); + if (manager->get_file_minor_ver() >= 40) { + _off_lights.resize(scan.get_uint16()); + for (int i = 0; i < _off_lights.size(); ++i) { + _off_lights[i].fillin(scan, manager); + } - aux->_num_off_lights = scan.get_uint16(); - manager->read_pointers(scan, aux->_num_off_lights); - - aux->_num_on_lights = scan.get_uint16(); - manager->read_pointers(scan, aux->_num_on_lights); + _on_lights.resize(scan.get_uint16()); + for (int i = 0; i < _on_lights.size(); ++i) { + _on_lights[i].fillin(scan, manager); + } + } else { + BamAuxData *aux = new BamAuxData; + manager->set_aux_data(this, "lights", aux); + + aux->_num_off_lights = scan.get_uint16(); + manager->read_pointers(scan, aux->_num_off_lights); + + aux->_num_on_lights = scan.get_uint16(); + manager->read_pointers(scan, aux->_num_on_lights); + } } diff --git a/panda/src/pgraph/loader.cxx b/panda/src/pgraph/loader.cxx index 1c3a000988..44cc41de60 100644 --- a/panda/src/pgraph/loader.cxx +++ b/panda/src/pgraph/loader.cxx @@ -357,7 +357,7 @@ try_load_file(const Filename &pathname, const LoaderOptions &options, if (result != (PandaNode *)NULL) { if (record != (BamCacheRecord *)NULL) { // Store the loaded model in the model cache. - record->set_data(result, result); + record->set_data(result); cache->store(record); } diff --git a/panda/src/pgraph/nodePath.cxx b/panda/src/pgraph/nodePath.cxx index 94b02fcf84..e5896cbcb8 100644 --- a/panda/src/pgraph/nodePath.cxx +++ b/panda/src/pgraph/nodePath.cxx @@ -6345,6 +6345,10 @@ write_bam_file(const Filename &filename) const { bool okflag = false; if (bam_file.open_write(filename)) { + // Tell the BamWriter which node is the root node, for making + // NodePaths relative to when writing them out to the file. + bam_file.get_writer()->set_root_node(node()); + if (bam_file.write_object(node())) { okflag = true; } @@ -6368,6 +6372,10 @@ write_bam_stream(ostream &out) const { bool okflag = false; if (bam_file.open_write(out)) { + // Tell the BamWriter which node is the root node, for making + // NodePaths relative to when writing them out to the file. + bam_file.get_writer()->set_root_node(node()); + if (bam_file.write_object(node())) { okflag = true; } @@ -6434,6 +6442,10 @@ encode_to_bam_stream(string &data, BamWriter *writer) const { num_nodes = 1; } + // Tell the BamWriter which node is the root node, for making + // NodePaths relative to when writing them out to the file. + writer->set_root_node(node()); + // Write an initial Datagram to represent the error type and // number of nodes. Datagram dg; @@ -7451,3 +7463,125 @@ r_find_all_materials(PandaNode *node, const RenderState *state, } } +//////////////////////////////////////////////////////////////////// +// Function: NodePath::write_datagram +// Access: Public +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void NodePath:: +write_datagram(BamWriter *manager, Datagram &dg) const { + PandaNode *root = DCAST(PandaNode, manager->get_root_node()); + + // We have no root node to measure from. + if (root == (PandaNode *)NULL || root == node()) { + manager->write_pointer(dg, node()); + manager->write_pointer(dg, NULL); + return; + } + + Thread *current_thread = Thread::get_current_thread(); + int pipeline_stage = current_thread->get_pipeline_stage(); + + // Record the chain of nodes from the root to this node. + pvector path; + NodePathComponent *comp = _head; + while (comp != NULL) { + PandaNode *node = comp->get_node(); + path.push_back(node); + + if (node == root) { + break; + } + + comp = comp->get_next(pipeline_stage, current_thread); + } + + if (comp == (NodePathComponent *)NULL) { + // We did not encounter the root node. Not much we can do. + manager->write_pointer(dg, node()); + manager->write_pointer(dg, NULL); + return; + } + + // Write out the nodes in reverse order, for fast reconstructing. + for (int i = path.size() - 1; i >= 0; --i) { + manager->write_pointer(dg, path[i]); + } + manager->write_pointer(dg, NULL); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::complete_pointers +// Access: Public +// Description: Receives an array of pointers, one for each time +// manager->read_pointer() was called in fillin(). +// Returns the number of pointers processed. +//////////////////////////////////////////////////////////////////// +int NodePath:: +complete_pointers(TypedWritable **p_list, BamReader *manager) { + int pi = 0; + PT(PandaNode) node = DCAST(PandaNode, p_list[pi++]); + if (node.is_null()) { + // An empty NodePath. + _head = (NodePathComponent *)NULL; + return pi; + } + + Thread *current_thread = Thread::get_current_thread(); + int pipeline_stage = current_thread->get_pipeline_stage(); + + // Take an arbitrary path to the root of the NodePath. This probably + // won't be ambiguous, as this is usually the root of the model or scene + // we are currently loading. + PT(NodePathComponent) comp = node->get_generic_component(false, pipeline_stage, current_thread); + nassertd(!comp.is_null()) { + while (p_list[pi++]) {} + return pi; + } + + // Build up the chain of NodePathComponents leading up to this node. + while (p_list[pi] != NULL) { + PT(PandaNode) node = DCAST(PandaNode, p_list[pi++]); + + LightReMutexHolder holder(node->_paths_lock); + + // First, walk through the list of NodePathComponents we already + // have on the child, looking for one that already exists, + // referencing the indicated parent component. + PandaNode::Paths::const_iterator it; + for (it = node->_paths.begin(); it != node->_paths.end(); ++it) { + if ((*it)->get_next(pipeline_stage, current_thread) == comp) { + // If we already have such a component, use that. + comp = (*it); + break; + } + } + + if (it == node->_paths.end()) { + // We don't already have a NodePathComponent referring to this + // parent-child relationship. Create a new one. Note that we can't + // verify that they are actually related because we may not have + // completed the node's pointers yet, so we trust that the .bam is right. + comp = new NodePathComponent(node, comp, pipeline_stage, current_thread); + node->_paths.insert(comp); + } + } + // One more for the final NULL node. + ++pi; + + _head = comp; + return pi; +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::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 NodePath. +//////////////////////////////////////////////////////////////////// +void NodePath:: +fillin(DatagramIterator &scan, BamReader *manager) { + while(manager->read_pointer(scan)) {}; +} diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index 0762600b2e..2ad15a06cb 100644 --- a/panda/src/pgraph/nodePath.h +++ b/panda/src/pgraph/nodePath.h @@ -994,6 +994,11 @@ private: static PStatCollector _get_transform_pcollector; static PStatCollector _verify_complete_pcollector; +public: + void write_datagram(BamWriter *manager, Datagram &dg) const; + int complete_pointers(TypedWritable **plist, BamReader *manager); + void fillin(DatagramIterator &scan, BamReader *manager); + public: static TypeHandle get_class_type() { return _type_handle; diff --git a/panda/src/pgraph/nodePathComponent.h b/panda/src/pgraph/nodePathComponent.h index c0d76f0e78..344170b000 100644 --- a/panda/src/pgraph/nodePathComponent.h +++ b/panda/src/pgraph/nodePathComponent.h @@ -129,6 +129,7 @@ public: private: static TypeHandle _type_handle; friend class PandaNode; + friend class NodePath; }; INLINE ostream &operator << (ostream &out, const NodePathComponent &comp); diff --git a/panda/src/pgraph/occluderEffect.cxx b/panda/src/pgraph/occluderEffect.cxx index 27405998d9..60a5ab0e9c 100644 --- a/panda/src/pgraph/occluderEffect.cxx +++ b/panda/src/pgraph/occluderEffect.cxx @@ -169,8 +169,7 @@ write_datagram(BamWriter *manager, Datagram &dg) { // write the on occluders pointers if any Occluders::const_iterator nti; for (nti = _on_occluders.begin(); nti != _on_occluders.end(); ++nti) { - NodePath occluder = (*nti); - manager->write_pointer(dg, occluder.node()); + (*nti).write_datagram(manager, dg); } } @@ -186,19 +185,32 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) { int pi = RenderEffect::complete_pointers(p_list, manager); AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr(); - Occluders::iterator ci; - ci = _on_occluders.begin(); - while (ci != _on_occluders.end()) { - PandaNode *node; - DCAST_INTO_R(node, p_list[pi++], pi); + if (manager->get_file_minor_ver() >= 40) { + for (int i = 0; i < _on_occluders.size(); ++i) { + pi += _on_occluders[i].complete_pointers(p_list + pi, manager); - int ni = areg->find_node(node->get_type(), node->get_name()); - if (ni != -1) { - (*ci) = areg->get_node(ni); - } else { - (*ci) = NodePath(node); + int n = areg->find_node(_on_occluders[i]); + if (n != -1) { + // If it's in the registry, replace it. + _on_occluders[i] = areg->get_node(n); + } + } + + } else { + Occluders::iterator ci; + ci = _on_occluders.begin(); + while (ci != _on_occluders.end()) { + PandaNode *node; + DCAST_INTO_R(node, p_list[pi++], pi); + + int ni = areg->find_node(node->get_type(), node->get_name()); + if (ni != -1) { + (*ci) = areg->get_node(ni); + } else { + (*ci) = NodePath(node); + } + ++ci; } - ++ci; } _on_occluders.sort(); @@ -250,13 +262,16 @@ make_from_bam(const FactoryParams ¶ms) { void OccluderEffect:: fillin(DatagramIterator &scan, BamReader *manager) { RenderEffect::fillin(scan, manager); - + // Push back an empty NodePath for each Occluder for now, until we // get the actual list of pointers later in complete_pointers(). int num_on_occluders = scan.get_uint16(); - _on_occluders.reserve(num_on_occluders); - for (int i = 0; i < num_on_occluders; i++) { - manager->read_pointer(scan); - _on_occluders.push_back(NodePath()); + _on_occluders.resize(num_on_occluders); + if (manager->get_file_minor_ver() >= 40) { + for (int i = 0; i < num_on_occluders; i++) { + _on_occluders[i].fillin(scan, manager); + } + } else { + manager->read_pointers(scan, num_on_occluders); } } diff --git a/panda/src/pgraph/paramNodePath.cxx b/panda/src/pgraph/paramNodePath.cxx index 00fb5be24a..8f39b69b6c 100644 --- a/panda/src/pgraph/paramNodePath.cxx +++ b/panda/src/pgraph/paramNodePath.cxx @@ -48,15 +48,7 @@ register_with_read_factory() { void ParamNodePath:: write_datagram(BamWriter *manager, Datagram &dg) { ParamValueBase::write_datagram(manager, dg); - - // We can't store a NodePath, so we store a pointer to the - // underlying node, and pray that there is an unambiguous path - // from the root to it. - if (_node_path.is_empty()) { - manager->write_pointer(dg, NULL); - } else { - manager->write_pointer(dg, _node_path.node()); - } + _node_path.write_datagram(manager, dg); } //////////////////////////////////////////////////////////////////// @@ -69,7 +61,12 @@ write_datagram(BamWriter *manager, Datagram &dg) { int ParamNodePath:: complete_pointers(TypedWritable **p_list, BamReader *manager) { int pi = ParamValueBase::complete_pointers(p_list, manager); - _node_path = NodePath(DCAST(PandaNode, p_list[pi++])); + + if (manager->get_file_minor_ver() >= 40) { + pi += _node_path.complete_pointers(p_list + pi, manager); + } else { + _node_path = NodePath(DCAST(PandaNode, p_list[pi++])); + } return pi; } @@ -104,5 +101,10 @@ make_from_bam(const FactoryParams ¶ms) { void ParamNodePath:: fillin(DatagramIterator &scan, BamReader *manager) { ParamValueBase::fillin(scan, manager); - manager->read_pointer(scan); + + if (manager->get_file_minor_ver() >= 40) { + _node_path.fillin(scan, manager); + } else { + manager->read_pointer(scan); + } } diff --git a/panda/src/putil/bam.h b/panda/src/putil/bam.h index 916d47afe3..ad3bd8ee3f 100644 --- a/panda/src/putil/bam.h +++ b/panda/src/putil/bam.h @@ -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 = 39; +static const unsigned short _bam_minor_ver = 40; // 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. @@ -60,5 +60,6 @@ static const unsigned short _bam_minor_ver = 39; // Bumped to minor version 37 on 1/22/15 to add GeomVertexArrayFormat::_divisor. // Bumped to minor version 38 on 4/15/15 to add various Bullet classes. // Bumped to minor version 39 on 1/9/16 to change lights and materials. +// Bumped to minor version 40 on 1/11/16 to make NodePaths writable. #endif diff --git a/panda/src/putil/bamCache.cxx b/panda/src/putil/bamCache.cxx index 7616350e07..23e8dece01 100644 --- a/panda/src/putil/bamCache.cxx +++ b/panda/src/putil/bamCache.cxx @@ -258,6 +258,12 @@ store(BamCacheRecord *record) { writer.set_file_texture_mode(BamWriter::BTM_fullpath); } + // This is necessary for relative NodePaths to work. + TypeHandle node_type = type_registry->find_type("PandaNode"); + if (record->get_data()->is_of_type(node_type)) { + writer.set_root_node(record->get_data()); + } + if (!writer.write_object(record)) { util_cat.error() << "Unable to write object to " << temp_pathname << "\n"; diff --git a/panda/src/putil/bamCacheRecord.I b/panda/src/putil/bamCacheRecord.I index 9679a70a45..53d3d91cf8 100644 --- a/panda/src/putil/bamCacheRecord.I +++ b/panda/src/putil/bamCacheRecord.I @@ -206,6 +206,28 @@ set_data(TypedWritable *ptr, ReferenceCount *ref_ptr) { } } +//////////////////////////////////////////////////////////////////// +// Function: BamCacheRecord::set_data +// Access: Published +// Description: This variant on set_data() is provided to easily +// pass objects deriving from TypedWritable. +//////////////////////////////////////////////////////////////////// +INLINE void BamCacheRecord:: +set_data(TypedWritable *ptr) { + set_data(ptr, ptr->as_reference_count()); +} + +//////////////////////////////////////////////////////////////////// +// Function: BamCacheRecord::set_data +// Access: Published +// Description: This variant on set_data() is provided to easily +// pass objects deriving from TypedWritableReferenceCount. +//////////////////////////////////////////////////////////////////// +INLINE void BamCacheRecord:: +set_data(TypedWritableReferenceCount *ptr) { + set_data((TypedWritable *)ptr, (ReferenceCount *)ptr); +} + //////////////////////////////////////////////////////////////////// // Function: BamCacheRecord::set_data // Access: Published diff --git a/panda/src/putil/bamCacheRecord.h b/panda/src/putil/bamCacheRecord.h index c6260141ac..523fadc78a 100644 --- a/panda/src/putil/bamCacheRecord.h +++ b/panda/src/putil/bamCacheRecord.h @@ -72,8 +72,12 @@ PUBLISHED: 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); + INLINE void set_data(TypedWritableReferenceCount *ptr); INLINE void set_data(TypedWritable *ptr, int dummy); + MAKE_PROPERTY2(data, has_data, get_data, set_data, clear_data); + void output(ostream &out) const; void write(ostream &out, int indent_level = 0) const; diff --git a/panda/src/putil/bamWriter.I b/panda/src/putil/bamWriter.I index 06e235825a..555eb9abb1 100644 --- a/panda/src/putil/bamWriter.I +++ b/panda/src/putil/bamWriter.I @@ -94,3 +94,27 @@ INLINE void BamWriter:: set_file_texture_mode(BamTextureMode file_texture_mode) { _file_texture_mode = file_texture_mode; } + +//////////////////////////////////////////////////////////////////// +// Function: BamWriter::get_root_node +// Access: Published +// Description: Returns the root node of the part of the scene +// graph we are currently writing out. This is used +// for determining what to make NodePaths relative to. +//////////////////////////////////////////////////////////////////// +INLINE TypedWritable *BamWriter:: +get_root_node() const { + return _root_node; +} + +//////////////////////////////////////////////////////////////////// +// Function: BamWriter::set_root_node +// Access: Published +// Description: Sets the root node of the part of the scene graph +// we are currently writing out. NodePaths written +// to this bam file will be relative to this node. +//////////////////////////////////////////////////////////////////// +INLINE void BamWriter:: +set_root_node(TypedWritable *root_node) { + _root_node = root_node; +} diff --git a/panda/src/putil/bamWriter.h b/panda/src/putil/bamWriter.h index 4d4529360f..674aa7044a 100644 --- a/panda/src/putil/bamWriter.h +++ b/panda/src/putil/bamWriter.h @@ -90,12 +90,16 @@ PUBLISHED: INLINE BamTextureMode get_file_texture_mode() const; INLINE void set_file_texture_mode(BamTextureMode file_texture_mode); + INLINE TypedWritable *get_root_node() const; + INLINE void set_root_node(TypedWritable *root_node); + PUBLISHED: MAKE_PROPERTY(target, get_target, set_target); MAKE_PROPERTY(filename, get_filename); MAKE_PROPERTY(file_endian, get_file_endian); MAKE_PROPERTY(file_stdfloat_double, get_file_stdfloat_double); MAKE_PROPERTY(file_texture_mode, get_file_texture_mode); + MAKE_PROPERTY(root_node, get_root_node, set_root_node); public: // Functions to support classes that write themselves to the Bam. @@ -125,6 +129,11 @@ private: bool _file_stdfloat_double; BamTextureMode _file_texture_mode; + // Stores the PandaNode representing the root of the node hierarchy + // we are currently writing, if any, for the purpose of writing NodePaths. + // This is a TypedWritable since PandaNode is defined in pgraph. + TypedWritable *_root_node; + // This is the set of all TypeHandles already written. pset _types_written;