bam 6.40: support writing NodePaths, allows instanced lights and clip planes

This commit is contained in:
rdb 2016-01-11 15:04:06 +01:00
parent 9b4ce5ec0a
commit 41fad59ae8
17 changed files with 464 additions and 154 deletions

View File

@ -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<class Key, class Compare, class Vector>
INLINE void ordered_vector<Key, Compare, 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<class Key, class Compare, class Vector>
INLINE void ordered_vector<Key, Compare, 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

View File

@ -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);

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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<PandaNode *> 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)) {};
}

View File

@ -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;

View File

@ -129,6 +129,7 @@ public:
private:
static TypeHandle _type_handle;
friend class PandaNode;
friend class NodePath;
};
INLINE ostream &operator << (ostream &out, const NodePathComponent &comp);

View File

@ -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 &params) {
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);
}
}

View File

@ -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 &params) {
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);
}
}

View File

@ -33,7 +33,7 @@ static const unsigned short _bam_major_ver = 6;
// Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData.
static const unsigned short _bam_first_minor_ver = 14;
static const unsigned short _bam_minor_ver = 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

View File

@ -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";

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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<int, int_hash> _types_written;