new pgraph bam rules, cdata copy constructors

This commit is contained in:
David Rose 2002-03-11 17:32:10 +00:00
parent d83cc1a60b
commit 9145e25ad4
69 changed files with 1409 additions and 756 deletions

View File

@ -64,7 +64,7 @@ void AnimBundleNode::
fillin(DatagramIterator& scan, BamReader* manager)
{
NamedNode::fillin(scan, manager);
manager->read_pointer(scan, this);
manager->read_pointer(scan);
}
////////////////////////////////////////////////////////////////////

View File

@ -205,11 +205,11 @@ void AnimGroup::
fillin(DatagramIterator& scan, BamReader* manager)
{
set_name(scan.get_string());
manager->read_pointer(scan, this);
manager->read_pointer(scan);
_num_children = scan.get_uint16();
for(int i = 0; i < _num_children; i++)
{
manager->read_pointer(scan, this);
manager->read_pointer(scan);
}
}

View File

@ -65,7 +65,7 @@ void PartBundleNode::
fillin(DatagramIterator& scan, BamReader* manager)
{
NamedNode::fillin(scan, manager);
manager->read_pointer(scan, this);
manager->read_pointer(scan);
}
////////////////////////////////////////////////////////////////////

View File

@ -497,7 +497,7 @@ fillin(DatagramIterator& scan, BamReader* manager)
_num_children = scan.get_uint16();
for(i = 0; i < _num_children; i++)
{
manager->read_pointer(scan, this);
manager->read_pointer(scan);
}
}

View File

@ -106,5 +106,5 @@ make_from_bam(const FactoryParams &params) {
void qpAnimBundleNode::
fillin(DatagramIterator &scan, BamReader* manager) {
PandaNode::fillin(scan, manager);
manager->read_pointer(scan, this);
manager->read_pointer(scan);
}

View File

@ -76,5 +76,5 @@ complete_pointers(TypedWritable **p_list, BamReader* manager) {
void qpPartBundleNode::
fillin(DatagramIterator &scan, BamReader* manager) {
PandaNode::fillin(scan, manager);
manager->read_pointer(scan, this);
manager->read_pointer(scan);
}

View File

@ -426,7 +426,7 @@ fillin(DatagramIterator& scan, BamReader* manager)
{
PartBundleNode::fillin(scan, manager);
_cv.fillin(scan, manager);
manager->read_pointer(scan, this);
manager->read_pointer(scan);
// Read the number of parts to expect in the _parts list, and then
// fill the array up with NULLs. We'll fill in the actual values in
@ -435,7 +435,7 @@ fillin(DatagramIterator& scan, BamReader* manager)
_parts.clear();
_parts.reserve(num_parts);
for (int i = 0; i < num_parts; i++) {
manager->read_pointer(scan, this);
manager->read_pointer(scan);
_parts.push_back((PartGroup *)NULL);
}

View File

@ -339,13 +339,13 @@ fillin(DatagramIterator& scan, BamReader* manager)
_num_net_arcs = scan.get_uint16();
for(i = 0; i < _num_net_arcs; i++)
{
manager->read_pointer(scan, this);
manager->read_pointer(scan);
}
_num_local_arcs = scan.get_uint16();
for(i = 0; i < _num_local_arcs; i++)
{
manager->read_pointer(scan, this);
manager->read_pointer(scan);
}
_initial_net_transform_inverse.read_datagram(scan);

View File

@ -515,7 +515,7 @@ void qpCharacter::
fillin(DatagramIterator &scan, BamReader *manager) {
qpPartBundleNode::fillin(scan, manager);
_cv.fillin(scan, manager);
manager->read_pointer(scan, this);
manager->read_pointer(scan);
// Read the number of parts to expect in the _parts list, and then
// fill the array up with NULLs. We'll fill in the actual values in
@ -524,7 +524,7 @@ fillin(DatagramIterator &scan, BamReader *manager) {
_parts.clear();
_parts.reserve(num_parts);
for (int i = 0; i < num_parts; i++) {
manager->read_pointer(scan, this);
manager->read_pointer(scan);
_parts.push_back((PartGroup *)NULL);
}

View File

@ -286,7 +286,7 @@ fillin(DatagramIterator& scan, BamReader* manager)
_solids.reserve(num_solids);
for(i = 0; i < num_solids; i++) {
manager->read_pointer(scan, this);
manager->read_pointer(scan);
_solids.push_back((CollisionSolid *)NULL);
}

View File

@ -34,7 +34,12 @@ TypeHandle GraphicsWindow::WindowPipe::_type_handle;
GraphicsWindow::WindowFactory *GraphicsWindow::_factory = NULL;
#if defined(DO_PSTATS) && !defined(CPPPARSER)
#ifndef CPPPARSER
// We must compile these lines, even if DO_PSTATS is not defined,
// because the symbols for them are declared in the header file.
// Otherwise they will be undefined symbols at link time. However,
// there's no runtime overhead to speak of for declaring these, so
// there's no harm in compiling them all the time.
PStatCollector GraphicsWindow::_app_pcollector("App");
PStatCollector GraphicsWindow::_show_code_pcollector("App:Show code");
PStatCollector GraphicsWindow::_swap_pcollector("Swap buffers");

View File

@ -449,14 +449,14 @@ fillin(DatagramIterator &scan, BamReader *manager)
_num_flares = scan.get_uint16();
for(i = 0; i < _num_flares; i++)
{
manager->read_pointer(scan, this);
manager->read_pointer(scan);
}
manager->read_pointer(scan, this);
manager->read_pointer(scan);
_num_arcs = scan.get_uint16();
for(i = 0; i < _num_arcs; i++)
{
manager->read_pointer(scan, this);
manager->read_pointer(scan);
}
size = scan.get_uint16();
@ -496,7 +496,7 @@ fillin(DatagramIterator &scan, BamReader *manager)
_blind_fall_off = scan.get_float32();
_flare_fall_off = scan.get_float32();
manager->read_pointer(scan, this);
manager->read_pointer(scan);
}
////////////////////////////////////////////////////////////////////

View File

@ -133,7 +133,7 @@ fillin(DatagramIterator& scan, BamReader* manager) {
_x_bind_type = (GeomBindType) scan.get_uint8();
_y_bind_type = (GeomBindType) scan.get_uint8();
_alpha_disable = (scan.get_uint8() !=0);
manager->read_pointer(scan, this);
manager->read_pointer(scan);
}
////////////////////////////////////////////////////////////////////

View File

@ -29,6 +29,31 @@ CData() {
_flags = F_bound_stale;
}
////////////////////////////////////////////////////////////////////
// Function: BoundedObject::CData::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE_GRAPH BoundedObject::CData::
CData(const BoundedObject::CData &copy) :
_flags(copy._flags),
_bound_type(copy._bound_type),
_bound(copy._bound)
{
}
////////////////////////////////////////////////////////////////////
// Function: BoundedObject::CData::Copy Assignment Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE_GRAPH void BoundedObject::CData::
operator = (const BoundedObject::CData &copy) {
_flags = copy._flags;
_bound_type = copy._bound_type;
_bound = copy._bound;
}
////////////////////////////////////////////////////////////////////
// Function: BoundedObject::Constructor
@ -45,12 +70,9 @@ BoundedObject() {
// Description:
////////////////////////////////////////////////////////////////////
INLINE_GRAPH BoundedObject::
BoundedObject(const BoundedObject &copy) {
CDWriter cdata(_cycler);
CDReader copy_cdata(copy._cycler);
cdata->_flags = copy_cdata->_flags;
cdata->_bound_type = copy_cdata->_bound_type;
cdata->_bound = copy_cdata->_bound;
BoundedObject(const BoundedObject &copy) :
_cycler(copy._cycler)
{
}
////////////////////////////////////////////////////////////////////
@ -60,11 +82,7 @@ BoundedObject(const BoundedObject &copy) {
////////////////////////////////////////////////////////////////////
INLINE_GRAPH void BoundedObject::
operator = (const BoundedObject &copy) {
CDWriter cdata(_cycler);
CDReader copy_cdata(copy._cycler);
cdata->_flags = copy_cdata->_flags;
cdata->_bound_type = copy_cdata->_bound_type;
cdata->_bound = copy_cdata->_bound;
_cycler = copy._cycler;
}
////////////////////////////////////////////////////////////////////
@ -77,8 +95,8 @@ operator = (const BoundedObject &copy) {
INLINE_GRAPH void BoundedObject::
set_bound(BoundedObject::BoundingVolumeType type) {
nassertv(type != BVT_static);
CDWriter cdata(_cycler);
mark_bound_stale();
CDWriter cdata(_cycler);
cdata->_bound_type = type;
}
@ -91,35 +109,13 @@ set_bound(BoundedObject::BoundingVolumeType type) {
////////////////////////////////////////////////////////////////////
INLINE_GRAPH void BoundedObject::
set_bound(const BoundingVolume &bound) {
CDWriter cdata(_cycler);
mark_bound_stale();
CDWriter cdata(_cycler);
cdata->_bound_type = BVT_static;
cdata->_flags &= ~F_bound_stale;
cdata->_bound = bound.make_copy();
}
////////////////////////////////////////////////////////////////////
// Function: BoundedObject::get_bound
// Access: Published
// Description: Returns the current bounding volume on this node,
// possibly forcing a recompute. A node's bounding
// volume encloses only the node itself, irrespective of
// the nodes above or below it in the graph. This is
// different from the bounding volumes on the arcs,
// which enclose all geometry below them.
////////////////////////////////////////////////////////////////////
INLINE_GRAPH const BoundingVolume &BoundedObject::
get_bound() const {
CDReader cdata(_cycler);
if (cdata->_bound_type == BVT_static) {
CDWriter cdata_w(((BoundedObject *)this)->_cycler);
cdata_w->_flags &= ~F_bound_stale;
} else if (is_bound_stale() || cdata->_bound == (BoundingVolume *)NULL) {
((BoundedObject *)this)->recompute_bound();
}
return *cdata->_bound;
}
////////////////////////////////////////////////////////////////////
// Function: BoundedObject::mark_bound_stale
// Access: Published
@ -135,8 +131,10 @@ mark_bound_stale() {
if (is_bound_stale()) {
return false;
}
CDWriter cdata(_cycler);
cdata->_flags |= F_bound_stale;
{
CDWriter cdata(_cycler);
cdata->_flags |= F_bound_stale;
}
propagate_stale_bound();
return true;
@ -151,8 +149,10 @@ mark_bound_stale() {
////////////////////////////////////////////////////////////////////
INLINE_GRAPH void BoundedObject::
force_bound_stale() {
CDWriter cdata(_cycler);
cdata->_flags |= F_bound_stale;
{
CDWriter cdata(_cycler);
cdata->_flags |= F_bound_stale;
}
propagate_stale_bound();
}

View File

@ -23,19 +23,6 @@
TypeHandle BoundedObject::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: BoundedObject::CData::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
BoundedObject::CData::
CData(const BoundedObject::CData &copy) :
_flags(copy._flags),
_bound_type(copy._bound_type),
_bound(copy._bound)
{
}
////////////////////////////////////////////////////////////////////
// Function: BoundedObject::Destructor
// Access: Public, Virtual
@ -45,6 +32,41 @@ BoundedObject::
~BoundedObject() {
}
////////////////////////////////////////////////////////////////////
// Function: BoundedObject::get_bound
// Access: Published
// Description: Returns the current bounding volume on this node,
// possibly forcing a recompute. A node's bounding
// volume encloses only the node itself, irrespective of
// the nodes above or below it in the graph. This is
// different from the bounding volumes on the arcs,
// which enclose all geometry below them.
////////////////////////////////////////////////////////////////////
INLINE_GRAPH const BoundingVolume &BoundedObject::
get_bound() const {
{
CDReader cdata(_cycler);
if (cdata->_bound_type == BVT_static) {
CDWriter cdata_w(((BoundedObject *)this)->_cycler, cdata);
cdata_w->_flags &= ~F_bound_stale;
return *cdata_w->_bound;
}
if (!is_bound_stale() && cdata->_bound != (BoundingVolume *)NULL) {
return *cdata->_bound;
}
// We need to recompute the bounding volume. First, we need to
// release the old CDReader, so we can get a CDReader in
// recompute_bound().
}
// Now it's safe to recompute the bounds.
((BoundedObject *)this)->recompute_bound();
CDReader cdata(_cycler);
return *cdata->_bound;
}
////////////////////////////////////////////////////////////////////
// Function: BoundedObject::CData::make_copy
// Access: Public, Virtual

View File

@ -52,7 +52,7 @@ PUBLISHED:
INLINE_GRAPH void set_bound(BoundingVolumeType type);
INLINE_GRAPH void set_bound(const BoundingVolume &volume);
INLINE_GRAPH const BoundingVolume &get_bound() const;
const BoundingVolume &get_bound() const;
INLINE_GRAPH bool mark_bound_stale();
INLINE_GRAPH void force_bound_stale();
@ -78,7 +78,9 @@ private:
class EXPCL_PANDA CData : public CycleData {
public:
INLINE_GRAPH CData();
CData(const CData &copy);
INLINE_GRAPH CData(const CData &copy);
INLINE_GRAPH void operator = (const CData &copy);
virtual CycleData *make_copy() const;
int _flags;

View File

@ -636,7 +636,7 @@ fillin(DatagramIterator &scan, BamReader *manager) {
while (num_types > 0) {
int num_arcs = scan.get_uint16();
while (num_arcs > 0) {
manager->read_pointer(scan, this);
manager->read_pointer(scan);
num_arcs--;
}
num_types--;
@ -666,7 +666,7 @@ fillin(DatagramIterator &scan, BamReader *manager) {
DownRelationPointers &drp = _connections[i].get_down();
int num_arcs = scan.get_uint16();
while (num_arcs > 0) {
manager->read_pointer(scan, this);
manager->read_pointer(scan);
drp.push_back((NodeRelation *)NULL);
num_arcs--;
}

View File

@ -984,9 +984,9 @@ fillin(DatagramIterator& scan, BamReader* manager)
{
_graph_type = manager->read_handle(scan);
//Read in my parent
manager->read_pointer(scan, this);
manager->read_pointer(scan);
//Read in my child
manager->read_pointer(scan, this);
manager->read_pointer(scan);
//Get my sort relation
_sort = scan.get_uint16();
@ -994,7 +994,7 @@ fillin(DatagramIterator& scan, BamReader* manager)
_num_transitions = scan.get_uint16();
for(int i = 0; i < _num_transitions; i++)
{
manager->read_pointer(scan, this);
manager->read_pointer(scan);
}
}

View File

@ -610,7 +610,7 @@ fillin(DatagramIterator &scan, BamReader *manager) {
size_t i;
for (i = 0; i < num_segs; i++) {
Curveseg seg;
manager->read_pointer(scan, this);
manager->read_pointer(scan);
seg._curve = (ParametricCurve *)NULL;
seg._tend = scan.get_float64();
_segs.push_back(seg);

View File

@ -192,5 +192,5 @@ fillin(DatagramIterator &scan, BamReader *manager) {
RenderAttrib::fillin(scan, manager);
// Read the _material pointer.
manager->read_pointer(scan, this);
manager->read_pointer(scan);
}

View File

@ -353,8 +353,10 @@ clear_state() {
////////////////////////////////////////////////////////////////////
INLINE void PandaNode::
set_transform(const TransformState *transform) {
CDWriter cdata(_cycler);
cdata->_transform = transform;
{
CDWriter cdata(_cycler);
cdata->_transform = transform;
}
mark_bound_stale();
}

View File

@ -53,6 +53,122 @@ make_copy() const {
return new CData(*this);
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::CData::write_datagram
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
void PandaNode::CData::
write_datagram(BamWriter *manager, Datagram &dg) const {
manager->write_pointer(dg, _state);
manager->write_pointer(dg, _transform);
// When we write a PandaNode, we write out its complete list of
// child node pointers, but we only write out the parent node
// pointers that have already been added to the bam file by a
// previous write operation. This is a bit of trickery that allows
// us to write out just a subgraph (instead of the complete graph)
// when we write out an arbitrary node in the graph, yet also allows
// us to keep nodes completely in sync when we use the bam format
// for streaming scene graph operations over the network.
int num_parents = 0;
Up::const_iterator ui;
for (ui = _up.begin(); ui != _up.end(); ++ui) {
PandaNode *parent_node = (*ui).get_parent();
if (manager->has_object(parent_node)) {
num_parents++;
}
}
nassertv(num_parents == (int)(PN_uint16)num_parents);
dg.add_uint16(num_parents);
for (ui = _up.begin(); ui != _up.end(); ++ui) {
PandaNode *parent_node = (*ui).get_parent();
if (manager->has_object(parent_node)) {
manager->write_pointer(dg, parent_node);
}
}
int num_children = _down.size();
nassertv(num_children == (int)(PN_uint16)num_children);
dg.add_uint16(num_children);
// **** We should smarten up the writing of the sort number--most of
// the time these will all be zero.
Down::const_iterator ci;
for (ci = _down.begin(); ci != _down.end(); ++ci) {
PandaNode *child_node = (*ci).get_child();
int sort = (*ci).get_sort();
manager->write_pointer(dg, child_node);
dg.add_int32(sort);
}
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::CData::complete_pointers
// Access: Public, Virtual
// Description: Receives an array of pointers, one for each time
// manager->read_pointer() was called in fillin().
// Returns the number of pointers processed.
////////////////////////////////////////////////////////////////////
int PandaNode::CData::
complete_pointers(TypedWritable **p_list, BamReader *manager) {
int pi = CycleData::complete_pointers(p_list, manager);
// Get the state and transform pointers.
_state = DCAST(RenderState, p_list[pi++]);
_transform = DCAST(TransformState, p_list[pi++]);
// Get the parent pointers.
Up::iterator ui;
for (ui = _up.begin(); ui != _up.end(); ++ui) {
PT(PandaNode) parent_node = DCAST(PandaNode, p_list[pi++]);
(*ui) = UpConnection(parent_node);
}
// Get the child pointers.
Down::iterator di;
for (di = _down.begin(); di != _down.end(); ++di) {
int sort = (*di).get_sort();
PT(PandaNode) child_node = DCAST(PandaNode, p_list[pi++]);
(*di) = DownConnection(child_node, sort);
}
return pi;
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::CData::fillin
// Access: Public, Virtual
// Description: This internal function is called by make_from_bam to
// read in all of the relevant data from the BamFile for
// the new PandaNode.
////////////////////////////////////////////////////////////////////
void PandaNode::CData::
fillin(DatagramIterator &scan, BamReader *manager) {
// Read the state and transform pointers.
manager->read_pointer(scan);
manager->read_pointer(scan);
int num_parents = scan.get_uint16();
// Read the list of parent nodes. Push back a NULL for each one.
_up.reserve(num_parents);
for (int i = 0; i < num_parents; i++) {
manager->read_pointer(scan);
_up.push_back(UpConnection(NULL));
}
int num_children = scan.get_uint16();
// Read the list of child nodes. Push back a NULL for each one.
_down.reserve(num_children);
for (int i = 0; i < num_children; i++) {
manager->read_pointer(scan);
int sort = scan.get_int32();
_down.push_back(DownConnection(NULL, sort));
}
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::Constructor
// Access: Published
@ -73,16 +189,22 @@ PandaNode::
~PandaNode() {
// We shouldn't have any parents left by the time we destruct, or
// there's a refcount fault somewhere.
CDReader cdata(_cycler);
nassertv(cdata->_up.empty());
#ifndef NDEBUG
{
CDReader cdata(_cycler);
nassertv(cdata->_up.empty());
}
#endif // NDEBUG
remove_all_children();
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::Copy Constructor
// Access: Public
// Description:
// Access: Protected
// Description: Do not call the copy constructor directly; instead,
// use make_copy() or copy_subgraph() to make a copy of
// a node.
////////////////////////////////////////////////////////////////////
PandaNode::
PandaNode(const PandaNode &copy) :
@ -101,29 +223,24 @@ PandaNode(const PandaNode &copy) :
////////////////////////////////////////////////////////////////////
// Function: PandaNode::Copy Assignment Operator
// Access: Public
// Description:
// Access: Private
// Description: Do not call the copy assignment operator at all. Use
// make_copy() or copy_subgraph() to make a copy of a
// node.
////////////////////////////////////////////////////////////////////
void PandaNode::
operator = (const PandaNode &copy) {
TypedWritable::operator = (copy);
Namable::operator = (copy);
ReferenceCount::operator = (copy);
// Copy the other node's state.
CDReader copy_cdata(copy._cycler);
CDWriter cdata(_cycler);
cdata->_state = copy_cdata->_state;
cdata->_transform = copy_cdata->_transform;
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::make_copy
// Access: Public, Virtual
// Description: Returns a newly-allocated PandaNode that is a shallow copy
// of this one. It will be a different pointer, but its
// internal data may or may not be shared with that of
// the original PandaNode. No children will be copied.
// Description: Returns a newly-allocated PandaNode that is a shallow
// copy of this one. It will be a different pointer,
// but its internal data may or may not be shared with
// that of the original PandaNode. No children will be
// copied.
////////////////////////////////////////////////////////////////////
PandaNode *PandaNode::
make_copy() const {
@ -361,29 +478,30 @@ find_child(PandaNode *node) const {
void PandaNode::
add_child(PandaNode *child_node, int sort) {
// Ensure the child_node is not deleted while we do this.
PT(PandaNode) keep_child = child_node;
remove_child(child_node);
CDWriter cdata(_cycler);
CDWriter cdata_child(child_node->_cycler);
cdata->_down.insert(DownConnection(child_node, sort));
cdata_child->_up.insert(UpConnection(this));
// We also have to adjust any qpNodePathComponents the child might
// have that reference the child as a top node. Any other
// components we can leave alone, because we are making a new
// instance of the child.
Chains::iterator ci;
for (ci = cdata_child->_chains.begin();
ci != cdata_child->_chains.end();
++ci) {
if ((*ci)->is_top_node()) {
(*ci)->set_next(get_generic_component());
{
PT(PandaNode) keep_child = child_node;
remove_child(child_node);
CDWriter cdata(_cycler);
CDWriter cdata_child(child_node->_cycler);
cdata->_down.insert(DownConnection(child_node, sort));
cdata_child->_up.insert(UpConnection(this));
// We also have to adjust any qpNodePathComponents the child might
// have that reference the child as a top node. Any other
// components we can leave alone, because we are making a new
// instance of the child.
Chains::iterator ci;
for (ci = cdata_child->_chains.begin();
ci != cdata_child->_chains.end();
++ci) {
if ((*ci)->is_top_node()) {
(*ci)->set_next(get_generic_component());
}
}
child_node->fix_chain_lengths(cdata_child);
}
child_node->fix_chain_lengths();
// Mark the bounding volumes stale.
force_bound_stale();
}
@ -395,45 +513,47 @@ add_child(PandaNode *child_node, int sort) {
////////////////////////////////////////////////////////////////////
void PandaNode::
remove_child(int n) {
CDWriter cdata(_cycler);
nassertv(n >= 0 && n < (int)cdata->_down.size());
PT(PandaNode) child_node = cdata->_down[n].get_child();
CDWriter cdata_child(child_node->_cycler);
cdata->_down.erase(cdata->_down.begin() + n);
int num_erased = cdata_child->_up.erase(UpConnection(this));
nassertv(num_erased == 1);
// Now sever any qpNodePathComponents on the child that reference
// this node. If we have multiple of these, we have to collapse
// them together.
qpNodePathComponent *collapsed = (qpNodePathComponent *)NULL;
Chains::iterator ci;
ci = cdata_child->_chains.begin();
while (ci != cdata_child->_chains.end()) {
Chains::iterator cnext = ci;
++cnext;
if (!(*ci)->is_top_node() && (*ci)->get_next()->get_node() == this) {
if (collapsed == (qpNodePathComponent *)NULL) {
(*ci)->set_top_node();
collapsed = (*ci);
} else {
// This is a different component that used to reference a
// different instance, but now it's all just the same topnode.
// We have to collapse this and the previous one together.
// However, there might be some qpNodePaths out there that
// still keep a pointer to this one, so we can't remove it
// altogether.
(*ci)->collapse_with(collapsed);
cdata_child->_chains.erase(ci);
{
CDWriter cdata(_cycler);
nassertv(n >= 0 && n < (int)cdata->_down.size());
PT(PandaNode) child_node = cdata->_down[n].get_child();
CDWriter cdata_child(child_node->_cycler);
cdata->_down.erase(cdata->_down.begin() + n);
int num_erased = cdata_child->_up.erase(UpConnection(this));
nassertv(num_erased == 1);
// Now sever any qpNodePathComponents on the child that reference
// this node. If we have multiple of these, we have to collapse
// them together.
qpNodePathComponent *collapsed = (qpNodePathComponent *)NULL;
Chains::iterator ci;
ci = cdata_child->_chains.begin();
while (ci != cdata_child->_chains.end()) {
Chains::iterator cnext = ci;
++cnext;
if (!(*ci)->is_top_node() && (*ci)->get_next()->get_node() == this) {
if (collapsed == (qpNodePathComponent *)NULL) {
(*ci)->set_top_node();
collapsed = (*ci);
} else {
// This is a different component that used to reference a
// different instance, but now it's all just the same topnode.
// We have to collapse this and the previous one together.
// However, there might be some qpNodePaths out there that
// still keep a pointer to this one, so we can't remove it
// altogether.
(*ci)->collapse_with(collapsed);
cdata_child->_chains.erase(ci);
}
}
ci = cnext;
}
ci = cnext;
child_node->fix_chain_lengths(cdata_child);
}
child_node->fix_chain_lengths();
// Mark the bounding volumes stale.
force_bound_stale();
}
@ -448,73 +568,20 @@ remove_child(int n) {
bool PandaNode::
remove_child(PandaNode *child_node) {
// Ensure the child_node is not deleted while we do this.
PT(PandaNode) keep_child = child_node;
CDWriter cdata_child(child_node->_cycler);
// First, look for and remove this node from the child's parent
// list.
int num_erased = cdata_child->_up.erase(UpConnection(this));
if (num_erased == 0) {
// No such node; it wasn't our child to begin with.
return false;
}
// Now sever any qpNodePathComponents on the child that reference
// this node. If we have multiple of these, we have to collapse
// them together (see above).
qpNodePathComponent *collapsed = (qpNodePathComponent *)NULL;
Chains::iterator ci;
ci = cdata_child->_chains.begin();
while (ci != cdata_child->_chains.end()) {
Chains::iterator cnext = ci;
++cnext;
if (!(*ci)->is_top_node() && (*ci)->get_next()->get_node() == this) {
if (collapsed == (qpNodePathComponent *)NULL) {
(*ci)->set_top_node();
collapsed = (*ci);
} else {
(*ci)->collapse_with(collapsed);
cdata_child->_chains.erase(ci);
}
}
ci = cnext;
}
child_node->fix_chain_lengths();
// Mark the bounding volumes stale.
force_bound_stale();
CDWriter cdata(_cycler);
// Now, look for and remove the child node from our down list.
Down::iterator di;
for (di = cdata->_down.begin(); di != cdata->_down.end(); ++di) {
if ((*di).get_child() == child_node) {
cdata->_down.erase(di);
return true;
}
}
// We shouldn't get here unless there was a parent-child mismatch.
nassertr(false, false);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::remove_all_children
// Access: Published
// Description: Removes all the children from the node at once.
////////////////////////////////////////////////////////////////////
void PandaNode::
remove_all_children() {
CDWriter cdata(_cycler);
Down::iterator ci;
for (ci = cdata->_down.begin(); ci != cdata->_down.end(); ++ci) {
PT(PandaNode) child_node = (*ci).get_child();
{
PT(PandaNode) keep_child = child_node;
CDWriter cdata(_cycler);
CDWriter cdata_child(child_node->_cycler);
cdata_child->_up.erase(UpConnection(this));
// First, look for and remove this node from the child's parent
// list.
int num_erased = cdata_child->_up.erase(UpConnection(this));
if (num_erased == 0) {
// No such node; it wasn't our child to begin with.
return false;
}
// Now sever any qpNodePathComponents on the child that reference
// this node. If we have multiple of these, we have to collapse
// them together (see above).
@ -525,18 +592,75 @@ remove_all_children() {
Chains::iterator cnext = ci;
++cnext;
if (!(*ci)->is_top_node() && (*ci)->get_next()->get_node() == this) {
if (collapsed == (qpNodePathComponent *)NULL) {
(*ci)->set_top_node();
collapsed = (*ci);
} else {
(*ci)->collapse_with(collapsed);
cdata_child->_chains.erase(ci);
}
if (collapsed == (qpNodePathComponent *)NULL) {
(*ci)->set_top_node();
collapsed = (*ci);
} else {
(*ci)->collapse_with(collapsed);
cdata_child->_chains.erase(ci);
}
}
ci = cnext;
}
child_node->fix_chain_lengths(cdata_child);
// Now, look for and remove the child node from our down list.
Down::iterator di;
bool found = false;
for (di = cdata->_down.begin(); di != cdata->_down.end() && !found; ++di) {
if ((*di).get_child() == child_node) {
cdata->_down.erase(di);
found = true;
}
}
child_node->fix_chain_lengths();
nassertr(found, false);
}
// Mark the bounding volumes stale.
force_bound_stale();
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::remove_all_children
// Access: Published
// Description: Removes all the children from the node at once.
////////////////////////////////////////////////////////////////////
void PandaNode::
remove_all_children() {
{
CDWriter cdata(_cycler);
Down::iterator ci;
for (ci = cdata->_down.begin(); ci != cdata->_down.end(); ++ci) {
PT(PandaNode) child_node = (*ci).get_child();
CDWriter cdata_child(child_node->_cycler);
cdata_child->_up.erase(UpConnection(this));
// Now sever any qpNodePathComponents on the child that reference
// this node. If we have multiple of these, we have to collapse
// them together (see above).
qpNodePathComponent *collapsed = (qpNodePathComponent *)NULL;
Chains::iterator ci;
ci = cdata_child->_chains.begin();
while (ci != cdata_child->_chains.end()) {
Chains::iterator cnext = ci;
++cnext;
if (!(*ci)->is_top_node() && (*ci)->get_next()->get_node() == this) {
if (collapsed == (qpNodePathComponent *)NULL) {
(*ci)->set_top_node();
collapsed = (*ci);
} else {
(*ci)->collapse_with(collapsed);
cdata_child->_chains.erase(ci);
}
}
ci = cnext;
}
child_node->fix_chain_lengths(cdata_child);
}
}
// Mark the bounding volumes stale.
@ -600,8 +724,8 @@ propagate_stale_bound() {
CDWriter cdata(_cycler);
Up::const_iterator ui;
for (ui = cdata->_up.begin(); ui != cdata->_up.end(); ++ui) {
PandaNode *parent = (*ui).get_parent();
parent->mark_bound_stale();
PandaNode *parent_node = (*ui).get_parent();
parent_node->mark_bound_stale();
}
}
@ -718,57 +842,58 @@ void PandaNode::
detach(qpNodePathComponent *child) {
nassertv(child != (qpNodePathComponent *)NULL);
nassertv(!child->is_top_node());
PandaNode *child_node = child->get_node();
PandaNode *parent_node = child->get_next()->get_node();
// Break the qpNodePathComponent connection.
child->set_top_node();
CDWriter cdata_child(child_node->_cycler);
// Any other components in the same child_node that previously
// referenced the same parent has now become invalid and must be
// collapsed into this one and removed from the chains set.
Chains::iterator ci;
ci = cdata_child->_chains.begin();
while (ci != cdata_child->_chains.end()) {
Chains::iterator cnext = ci;
++cnext;
if ((*ci) != child && !(*ci)->is_top_node() &&
(*ci)->get_next()->get_node() == parent_node) {
(*ci)->collapse_with(child);
cdata_child->_chains.erase(ci);
{
// Break the qpNodePathComponent connection.
child->set_top_node();
CDWriter cdata_child(child_node->_cycler);
CDWriter cdata_parent(parent_node->_cycler);
// Any other components in the same child_node that previously
// referenced the same parent has now become invalid and must be
// collapsed into this one and removed from the chains set.
Chains::iterator ci;
ci = cdata_child->_chains.begin();
while (ci != cdata_child->_chains.end()) {
Chains::iterator cnext = ci;
++cnext;
if ((*ci) != child && !(*ci)->is_top_node() &&
(*ci)->get_next()->get_node() == parent_node) {
(*ci)->collapse_with(child);
cdata_child->_chains.erase(ci);
}
ci = cnext;
}
ci = cnext;
// Now look for the child and break the actual connection.
// First, look for and remove the parent node from the child's up
// list.
int num_erased = cdata_child->_up.erase(UpConnection(parent_node));
nassertv(num_erased == 1);
child_node->fix_chain_lengths(cdata_child);
// Now, look for and remove the child node from the parent's down list.
Down::iterator di;
bool found = false;
for (di = cdata_parent->_down.begin();
di != cdata_parent->_down.end() && !found;
++di) {
if ((*di).get_child() == child_node) {
cdata_parent->_down.erase(di);
found = true;
}
}
nassertv(found);
}
child_node->fix_chain_lengths();
// Mark the bounding volumes stale.
parent_node->force_bound_stale();
// Now look for the child and break the actual connection.
// First, look for and remove the parent node from the child's up
// list.
int num_erased = cdata_child->_up.erase(UpConnection(parent_node));
nassertv(num_erased == 1);
CDWriter cdata_parent(parent_node->_cycler);
// Now, look for and remove the child node from the parent's down list.
Down::iterator di;
for (di = cdata_parent->_down.begin();
di != cdata_parent->_down.end();
++di) {
if ((*di).get_child() == child_node) {
cdata_parent->_down.erase(di);
return;
}
}
// We shouldn't get here unless there was a parent-child mismatch.
nassertv(false);
}
////////////////////////////////////////////////////////////////////
@ -791,15 +916,17 @@ reparent(qpNodePathComponent *new_parent, qpNodePathComponent *child, int sort)
PandaNode *child_node = child->get_node();
PandaNode *parent_node = new_parent->get_node();
// Now reattach at the indicated sort position.
CDWriter cdata_parent(parent_node->_cycler);
CDWriter cdata_child(child_node->_cycler);
cdata_parent->_down.insert(DownConnection(child_node, sort));
cdata_child->_up.insert(UpConnection(parent_node));
cdata_child->_chains.insert(child);
child_node->fix_chain_lengths();
{
// Now reattach at the indicated sort position.
CDWriter cdata_parent(parent_node->_cycler);
CDWriter cdata_child(child_node->_cycler);
cdata_parent->_down.insert(DownConnection(child_node, sort));
cdata_child->_up.insert(UpConnection(parent_node));
cdata_child->_chains.insert(child);
child_node->fix_chain_lengths(cdata_child);
}
// Mark the bounding volumes stale.
parent_node->force_bound_stale();
@ -947,8 +1074,7 @@ delete_component(qpNodePathComponent *component) {
// these up.
////////////////////////////////////////////////////////////////////
void PandaNode::
fix_chain_lengths() {
CDReader cdata(_cycler);
fix_chain_lengths(const CData *cdata) {
bool any_wrong = false;
Chains::const_iterator ci;
@ -964,7 +1090,9 @@ fix_chain_lengths() {
if (any_wrong) {
Down::const_iterator di;
for (di = cdata->_down.begin(); di != cdata->_down.end(); ++di) {
(*di).get_child()->fix_chain_lengths();
PandaNode *child_node = (*di).get_child();
CDReader cdata_child(child_node->_cycler);
child_node->fix_chain_lengths(cdata_child);
}
}
}
@ -1012,57 +1140,9 @@ register_with_read_factory() {
////////////////////////////////////////////////////////////////////
void PandaNode::
write_datagram(BamWriter *manager, Datagram &dg) {
CDReader cdata(_cycler);
dg.add_string(get_name());
manager->write_pointer(dg, cdata->_state);
manager->write_pointer(dg, cdata->_transform);
// When we write a PandaNode, we write out its list of child nodes,
// but not its parent nodes--so that writing out a node implicitly
// writes out all of the nodes in the subgraph below, but not the
// nodes above as well.
int num_children = cdata->_down.size();
nassertv(num_children == (int)(PN_uint16)num_children);
dg.add_uint16(num_children);
// **** We should smarten up the writing of the sort number--most of
// the time these will all be zero.
Down::const_iterator ci;
for (ci = cdata->_down.begin(); ci != cdata->_down.end(); ++ci) {
PandaNode *child = (*ci).get_child();
int sort = (*ci).get_sort();
manager->write_pointer(dg, child);
dg.add_int32(sort);
}
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::complete_pointers
// Access: Public, Virtual
// Description: Receives an array of pointers, one for each time
// manager->read_pointer() was called in fillin().
// Returns the number of pointers processed.
////////////////////////////////////////////////////////////////////
int PandaNode::
complete_pointers(TypedWritable **p_list, BamReader *manager) {
CDWriter cdata(_cycler);
int pi = TypedWritable::complete_pointers(p_list, manager);
// Get the state and transform pointers.
cdata->_state = DCAST(RenderState, p_list[pi++]);
cdata->_transform = DCAST(TransformState, p_list[pi++]);
// Get the child pointers.
Down::iterator ci;
for (ci = cdata->_down.begin(); ci != cdata->_down.end(); ++ci) {
int sort = (*ci).get_sort();
PT(PandaNode) node = DCAST(PandaNode, p_list[pi++]);
(*ci) = DownConnection(node, sort);
}
return pi;
manager->write_cdata(dg, _cycler);
}
////////////////////////////////////////////////////////////////////
@ -1094,23 +1174,10 @@ make_from_bam(const FactoryParams &params) {
////////////////////////////////////////////////////////////////////
void PandaNode::
fillin(DatagramIterator &scan, BamReader *manager) {
CDWriter cdata(_cycler);
TypedWritable::fillin(scan, manager);
string name = scan.get_string();
set_name(name);
// Read the state and transform pointers.
manager->read_pointer(scan, this);
manager->read_pointer(scan, this);
int num_children = scan.get_uint16();
// Read the list of child nodes. Push back a NULL for each one.
cdata->_down.reserve(num_children);
for (int i = 0; i < num_children; i++) {
manager->read_pointer(scan, this);
int sort = scan.get_int32();
cdata->_down.push_back(DownConnection(NULL, sort));
}
manager->read_cdata(scan, _cycler);
}

View File

@ -53,10 +53,12 @@ PUBLISHED:
PandaNode(const string &name);
virtual ~PandaNode();
public:
protected:
PandaNode(const PandaNode &copy);
private:
void operator = (const PandaNode &copy);
public:
virtual PandaNode *make_copy() const;
PandaNode *copy_subgraph() const;
@ -161,7 +163,8 @@ private:
static PT(qpNodePathComponent) get_top_component(PandaNode *child);
PT(qpNodePathComponent) get_generic_component();
void delete_component(qpNodePathComponent *component);
void fix_chain_lengths();
class CData;
void fix_chain_lengths(const CData *cdata);
void r_list_descendants(ostream &out, int indent_level) const;
private:
@ -207,6 +210,9 @@ private:
INLINE CData();
CData(const CData &copy);
virtual CycleData *make_copy() const;
virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
virtual void fillin(DatagramIterator &scan, BamReader *manager);
Down _down;
Up _up;
@ -242,8 +248,6 @@ public:
public:
static void register_with_read_factory();
virtual void write_datagram(BamWriter *manager, Datagram &dg);
virtual int complete_pointers(TypedWritable **plist,
BamReader *manager);
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);

View File

@ -37,7 +37,7 @@ qpCamera(const string &name) :
////////////////////////////////////////////////////////////////////
// Function: qpCamera::Copy Constructor
// Access: Public
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
qpCamera::
@ -48,18 +48,6 @@ qpCamera(const qpCamera &copy) :
{
}
////////////////////////////////////////////////////////////////////
// Function: qpCamera::Copy Assignment Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void qpCamera::
operator = (const qpCamera &copy) {
qpLensNode::operator = (copy);
_active = copy._active;
_scene = copy._scene;
}
////////////////////////////////////////////////////////////////////
// Function: qpCamera::Destructor
// Access: Public, Virtual

View File

@ -36,9 +36,9 @@ class EXPCL_PANDA qpCamera : public qpLensNode {
PUBLISHED:
qpCamera(const string &name);
public:
protected:
qpCamera(const qpCamera &copy);
void operator = (const qpCamera &copy);
public:
virtual ~qpCamera();
virtual PandaNode *make_copy() const;

View File

@ -46,6 +46,67 @@ make_copy() const {
return new CData(*this);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomNode::CData::write_datagram
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
void qpGeomNode::CData::
write_datagram(BamWriter *manager, Datagram &dg) const {
int num_geoms = _geoms.size();
nassertv(num_geoms == (int)(PN_uint16)num_geoms);
dg.add_uint16(num_geoms);
Geoms::const_iterator gi;
for (gi = _geoms.begin(); gi != _geoms.end(); ++gi) {
const GeomEntry &entry = (*gi);
manager->write_pointer(dg, entry._geom);
manager->write_pointer(dg, entry._state);
}
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomNode::CData::complete_pointers
// Access: Public, Virtual
// Description: Receives an array of pointers, one for each time
// manager->read_pointer() was called in fillin().
// Returns the number of pointers processed.
////////////////////////////////////////////////////////////////////
int qpGeomNode::CData::
complete_pointers(TypedWritable **p_list, BamReader *manager) {
int pi = CycleData::complete_pointers(p_list, manager);
// Get the geom and state pointers.
Geoms::iterator gi;
for (gi = _geoms.begin(); gi != _geoms.end(); ++gi) {
GeomEntry &entry = (*gi);
entry._geom = DCAST(Geom, p_list[pi++]);
entry._state = DCAST(RenderState, p_list[pi++]);
}
return pi;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomNode::CData::fillin
// Access: Public, Virtual
// Description: This internal function is called by make_from_bam to
// read in all of the relevant data from the BamFile for
// the new qpGeomNode.
////////////////////////////////////////////////////////////////////
void qpGeomNode::CData::
fillin(DatagramIterator &scan, BamReader *manager) {
int num_geoms = scan.get_uint16();
// Read the list of geoms and states. Push back a NULL for each one.
_geoms.reserve(num_geoms);
for (int i = 0; i < num_geoms; i++) {
manager->read_pointer(scan);
manager->read_pointer(scan);
_geoms.push_back(GeomEntry(NULL, NULL));
}
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomNode::Constructor
// Access: Published
@ -59,37 +120,19 @@ qpGeomNode(const string &name) :
////////////////////////////////////////////////////////////////////
// Function: qpGeomNode::Copy Constructor
// Access: Published
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
qpGeomNode::
qpGeomNode(const qpGeomNode &copy) :
PandaNode(copy)
PandaNode(copy),
_cycler(copy._cycler)
{
// Copy the other node's _geoms.
CDReader copy_cdata(copy._cycler);
CDWriter cdata(_cycler);
cdata->_geoms = copy_cdata->_geoms;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomNode::Copy Assignment Operator
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
void qpGeomNode::
operator = (const qpGeomNode &copy) {
PandaNode::operator = (copy);
// Copy the other node's _geoms.
CDReader copy_cdata(copy._cycler);
CDWriter cdata(_cycler);
cdata->_geoms = copy_cdata->_geoms;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomNode::Destructor
// Access: Published, Virtual
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
qpGeomNode::
@ -212,42 +255,7 @@ register_with_read_factory() {
void qpGeomNode::
write_datagram(BamWriter *manager, Datagram &dg) {
PandaNode::write_datagram(manager, dg);
CDReader cdata(_cycler);
int num_geoms = cdata->_geoms.size();
nassertv(num_geoms == (int)(PN_uint16)num_geoms);
dg.add_uint16(num_geoms);
Geoms::const_iterator gi;
for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
const GeomEntry &entry = (*gi);
manager->write_pointer(dg, entry._geom);
manager->write_pointer(dg, entry._state);
}
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomNode::complete_pointers
// Access: Public, Virtual
// Description: Receives an array of pointers, one for each time
// manager->read_pointer() was called in fillin().
// Returns the number of pointers processed.
////////////////////////////////////////////////////////////////////
int qpGeomNode::
complete_pointers(TypedWritable **p_list, BamReader *manager) {
CDWriter cdata(_cycler);
int pi = PandaNode::complete_pointers(p_list, manager);
// Get the geom and state pointers.
Geoms::iterator gi;
for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
GeomEntry &entry = (*gi);
entry._geom = DCAST(Geom, p_list[pi++]);
entry._state = DCAST(RenderState, p_list[pi++]);
}
return pi;
manager->write_cdata(dg, _cycler);
}
////////////////////////////////////////////////////////////////////
@ -279,16 +287,6 @@ make_from_bam(const FactoryParams &params) {
////////////////////////////////////////////////////////////////////
void qpGeomNode::
fillin(DatagramIterator &scan, BamReader *manager) {
CDWriter cdata(_cycler);
PandaNode::fillin(scan, manager);
int num_geoms = scan.get_uint16();
// Read the list of geoms and states. Push back a NULL for each one.
cdata->_geoms.reserve(num_geoms);
for (int i = 0; i < num_geoms; i++) {
manager->read_pointer(scan, this);
manager->read_pointer(scan, this);
cdata->_geoms.push_back(GeomEntry(NULL, NULL));
}
manager->read_cdata(scan, _cycler);
}

View File

@ -39,9 +39,9 @@ class EXPCL_PANDA qpGeomNode : public PandaNode {
PUBLISHED:
qpGeomNode(const string &name);
public:
protected:
qpGeomNode(const qpGeomNode &copy);
void operator = (const qpGeomNode &copy);
public:
virtual ~qpGeomNode();
PUBLISHED:
@ -80,6 +80,9 @@ private:
INLINE CData();
CData(const CData &copy);
virtual CycleData *make_copy() const;
virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
virtual void fillin(DatagramIterator &scan, BamReader *manager);
Geoms _geoms;
};
@ -91,8 +94,6 @@ private:
public:
static void register_with_read_factory();
virtual void write_datagram(BamWriter *manager, Datagram &dg);
virtual int complete_pointers(TypedWritable **plist,
BamReader *manager);
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);

View File

@ -30,7 +30,7 @@ qpLensNode(const string &name) :
////////////////////////////////////////////////////////////////////
// Function: qpLensNode::Copy Constructor
// Access: Public
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
INLINE qpLensNode::
@ -40,17 +40,6 @@ qpLensNode(const qpLensNode &copy) :
{
}
////////////////////////////////////////////////////////////////////
// Function: qpLensNode::Copy Assignment Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void qpLensNode::
operator = (const qpLensNode &copy) {
PandaNode::operator = (copy);
_lens = copy._lens;
}
////////////////////////////////////////////////////////////////////
// Function: copy_lens
// Access: Public

View File

@ -36,10 +36,9 @@ class EXPCL_PANDA qpLensNode : public PandaNode {
PUBLISHED:
INLINE qpLensNode(const string &name);
public:
protected:
INLINE qpLensNode(const qpLensNode &copy);
INLINE void operator = (const qpLensNode &copy);
public:
virtual void output(ostream &out) const;
virtual void write(ostream &out, int indent_level = 0) const;

View File

@ -47,6 +47,18 @@ qpLODNode(const string &name) :
{
}
////////////////////////////////////////////////////////////////////
// Function: qpLODNode::Copy Constructor
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
INLINE qpLODNode::
qpLODNode(const qpLODNode &copy) :
SelectiveChildNode(copy),
_cycler(copy._cycler)
{
}
////////////////////////////////////////////////////////////////////
// Function: qpLODNode::add_switch
// Access: Published

View File

@ -32,33 +32,26 @@ make_copy() const {
}
////////////////////////////////////////////////////////////////////
// Function: qpLODNode::Copy Constructor
// Access: Public
// Description:
// Function: qpLODNode::CData::write_datagram
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
qpLODNode::
qpLODNode(const qpLODNode &copy) :
SelectiveChildNode(copy)
{
CDWriter cdata(_cycler);
CDReader cdata_copy(copy._cycler);
cdata->_lod = cdata_copy->_lod;
void qpLODNode::CData::
write_datagram(BamWriter *manager, Datagram &dg) const {
_lod.write_datagram(dg);
}
////////////////////////////////////////////////////////////////////
// Function: qpLODNode::Copy Assignment Operator
// Access: Public
// Description:
// Function: qpLODNode::CData::fillin
// Access: Public, Virtual
// Description: This internal function is called by make_from_bam to
// read in all of the relevant data from the BamFile for
// the new qpLODNode.
////////////////////////////////////////////////////////////////////
void qpLODNode::
operator = (const qpLODNode &copy) {
SelectiveChildNode::operator = (copy);
CDWriter cdata(_cycler);
CDReader cdata_copy(copy._cycler);
cdata->_lod = cdata_copy->_lod;
void qpLODNode::CData::
fillin(DatagramIterator &scan, BamReader *manager) {
_lod.read_datagram(scan);
}
////////////////////////////////////////////////////////////////////
@ -177,9 +170,7 @@ register_with_read_factory() {
void qpLODNode::
write_datagram(BamWriter *manager, Datagram &dg) {
SelectiveChildNode::write_datagram(manager, dg);
CDReader cdata(_cycler);
cdata->_lod.write_datagram(dg);
manager->write_cdata(dg, _cycler);
}
////////////////////////////////////////////////////////////////////
@ -212,7 +203,5 @@ make_from_bam(const FactoryParams &params) {
void qpLODNode::
fillin(DatagramIterator &scan, BamReader *manager) {
SelectiveChildNode::fillin(scan, manager);
CDWriter cdata(_cycler);
cdata->_lod.read_datagram(scan);
manager->read_cdata(scan, _cycler);
}

View File

@ -36,10 +36,9 @@ class EXPCL_PANDA qpLODNode : public SelectiveChildNode {
PUBLISHED:
INLINE qpLODNode(const string &name);
public:
protected:
INLINE qpLODNode(const qpLODNode &copy);
INLINE void operator = (const qpLODNode &copy);
public:
virtual PandaNode *make_copy() const;
virtual void xform(const LMatrix4f &mat);
virtual bool has_cull_callback() const;
@ -78,6 +77,8 @@ private:
INLINE CData();
INLINE CData(const CData &copy);
virtual CycleData *make_copy() const;
virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
virtual void fillin(DatagramIterator &scan, BamReader *manager);
LOD _lod;
};

View File

@ -136,8 +136,8 @@ is_collapsed() const {
////////////////////////////////////////////////////////////////////
INLINE int qpNodePathComponent::
get_length() const {
CDReader cdata(_cycler);
nassertr(!is_collapsed(), 0);
CDReader cdata(_cycler);
return cdata->_length;
}
@ -150,8 +150,8 @@ get_length() const {
////////////////////////////////////////////////////////////////////
INLINE qpNodePathComponent *qpNodePathComponent::
get_collapsed() const {
CDReader cdata(_cycler);
nassertr(is_collapsed(), (qpNodePathComponent *)NULL);
CDReader cdata(_cycler);
return cdata->_next;
}
@ -162,9 +162,9 @@ get_collapsed() const {
////////////////////////////////////////////////////////////////////
INLINE void qpNodePathComponent::
set_next(qpNodePathComponent *next) {
CDWriter cdata(_cycler);
nassertv(!is_collapsed());
nassertv(next != (qpNodePathComponent *)NULL);
CDWriter cdata(_cycler);
cdata->_next = next;
}
@ -176,8 +176,8 @@ set_next(qpNodePathComponent *next) {
////////////////////////////////////////////////////////////////////
INLINE void qpNodePathComponent::
set_top_node() {
CDWriter cdata(_cycler);
nassertv(!is_collapsed());
CDWriter cdata(_cycler);
cdata->_next = (qpNodePathComponent *)NULL;
}
@ -192,9 +192,9 @@ set_top_node() {
////////////////////////////////////////////////////////////////////
INLINE void qpNodePathComponent::
collapse_with(qpNodePathComponent *next) {
CDWriter cdata(_cycler);
nassertv(!is_collapsed());
nassertv(next != (qpNodePathComponent *)NULL);
CDWriter cdata(_cycler);
cdata->_next = next;
cdata->_length = 0;

View File

@ -31,38 +31,47 @@ make_copy() const {
return new CData(*this);
}
////////////////////////////////////////////////////////////////////
// Function: qpSequenceNode::CData::write_datagram
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
void qpSequenceNode::CData::
write_datagram(BamWriter *manager, Datagram &dg) const {
dg.add_float32(_cycle_rate);
float now = ClockObject::get_global_clock()->get_frame_time();
float frame = (now - _start_time) * _cycle_rate + _frame_offset;
dg.add_float32(frame);
}
////////////////////////////////////////////////////////////////////
// Function: qpSequenceNode::CData::fillin
// Access: Public, Virtual
// Description: This internal function is called by make_from_bam to
// read in all of the relevant data from the BamFile for
// the new qpSequenceNode.
////////////////////////////////////////////////////////////////////
void qpSequenceNode::CData::
fillin(DatagramIterator &scan, BamReader *manager) {
_cycle_rate = scan.get_float32();
_frame_offset = scan.get_float32();
float now = ClockObject::get_global_clock()->get_frame_time();
_start_time = now;
}
////////////////////////////////////////////////////////////////////
// Function: qpSequenceNode::Copy Constructor
// Access: Public
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
qpSequenceNode::
qpSequenceNode(const qpSequenceNode &copy) :
SelectiveChildNode(copy)
SelectiveChildNode(copy),
_cycler(copy._cycler)
{
CDWriter cdata(_cycler);
CDReader cdata_copy(copy._cycler);
cdata->_cycle_rate = cdata_copy->_cycle_rate;
cdata->_start_time = cdata_copy->_start_time;
cdata->_frame_offset = cdata_copy->_frame_offset;
}
////////////////////////////////////////////////////////////////////
// Function: qpSequenceNode::Copy Assignment Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void qpSequenceNode::
operator = (const qpSequenceNode &copy) {
SelectiveChildNode::operator = (copy);
CDWriter cdata(_cycler);
CDReader cdata_copy(copy._cycler);
cdata->_cycle_rate = cdata_copy->_cycle_rate;
cdata->_start_time = cdata_copy->_start_time;
cdata->_frame_offset = cdata_copy->_frame_offset;
}
////////////////////////////////////////////////////////////////////
@ -137,10 +146,7 @@ register_with_read_factory() {
void qpSequenceNode::
write_datagram(BamWriter *manager, Datagram &dg) {
SelectiveChildNode::write_datagram(manager, dg);
CDReader cdata(_cycler);
dg.add_float32(cdata->_cycle_rate);
dg.add_float32(calc_frame());
manager->write_cdata(dg, _cycler);
}
////////////////////////////////////////////////////////////////////
@ -173,11 +179,5 @@ make_from_bam(const FactoryParams &params) {
void qpSequenceNode::
fillin(DatagramIterator &scan, BamReader *manager) {
SelectiveChildNode::fillin(scan, manager);
CDWriter cdata(_cycler);
cdata->_cycle_rate = scan.get_float32();
cdata->_frame_offset = scan.get_float32();
float now = ClockObject::get_global_clock()->get_frame_time();
cdata->_start_time = now;
manager->read_cdata(scan, _cycler);
}

View File

@ -35,7 +35,6 @@ PUBLISHED:
public:
qpSequenceNode(const qpSequenceNode &copy);
void operator = (const qpSequenceNode &copy);
virtual PandaNode *make_copy() const;
@ -57,6 +56,8 @@ private:
INLINE CData();
INLINE CData(const CData &copy);
virtual CycleData *make_copy() const;
virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
virtual void fillin(DatagramIterator &scan, BamReader *manager);
float _cycle_rate;
float _frame_offset;

View File

@ -1080,7 +1080,7 @@ fillin(DatagramIterator &scan, BamReader *manager) {
// the actual list of pointers later in complete_pointers().
_attributes.reserve(num_attribs);
for (int i = 0; i < num_attribs; i++) {
manager->read_pointer(scan, this);
manager->read_pointer(scan);
int override = scan.get_int32();
_attributes.push_back(Attribute(override));
}

View File

@ -31,7 +31,7 @@ SelectiveChildNode(const string &name) :
////////////////////////////////////////////////////////////////////
// Function: SelectiveChildNode::Copy Constructor
// Access: Public
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
INLINE SelectiveChildNode::
@ -41,17 +41,6 @@ SelectiveChildNode(const SelectiveChildNode &copy) :
{
}
////////////////////////////////////////////////////////////////////
// Function: SelectiveChildNode::Copy Assignment Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void SelectiveChildNode::
operator = (const SelectiveChildNode &copy) {
PandaNode::operator = (copy);
_selected_child = copy._selected_child;
}
////////////////////////////////////////////////////////////////////
// Function: SelectiveChildNode::select_child
// Access: Protected

View File

@ -32,10 +32,10 @@ class EXPCL_PANDA SelectiveChildNode : public PandaNode {
PUBLISHED:
INLINE SelectiveChildNode(const string &name);
public:
protected:
INLINE SelectiveChildNode(const SelectiveChildNode &copy);
INLINE void operator = (const SelectiveChildNode &copy);
public:
virtual bool has_selective_visibility() const;
virtual int get_first_visible_child() const;
virtual int get_next_visible_child(int n) const;
@ -44,6 +44,10 @@ protected:
INLINE void select_child(int n);
private:
// Not sure if this should be cycled or not. It's not exactly
// thread-safe not to cycle it, but it doesn't really need the full
// pipeline control. It's probably a problem in the non-thread-safe
// design; need to rethink the design a bit.
int _selected_child;
public:

View File

@ -192,5 +192,5 @@ fillin(DatagramIterator &scan, BamReader *manager) {
RenderAttrib::fillin(scan, manager);
// Read the _texture pointer.
manager->read_pointer(scan, this);
manager->read_pointer(scan);
}

View File

@ -16,13 +16,14 @@
//
////////////////////////////////////////////////////////////////////
#include <pandabase.h>
#include <notify.h>
#include "pandabase.h"
#include "notify.h"
#include "bam.h"
#include "bamReader.h"
#include <datagramIterator.h>
#include "datagramIterator.h"
#include "config_util.h"
#include "pipelineCyclerBase.h"
WritableFactory *BamReader::_factory = (WritableFactory*)0L;
BamReader *const BamReader::Null = (BamReader*)0L;
@ -43,6 +44,7 @@ BamReader(DatagramGenerator *generator)
{
_num_extra_objects = 0;
_now_creating = _created_objs.end();
_reading_cycler = (PipelineCyclerBase *)NULL;
_pta_id = -1;
}
@ -225,71 +227,25 @@ resolve() {
any_completed_this_pass = false;
// Walk through all the objects that still have outstanding pointers.
Requests::iterator ri;
ri = _deferred_pointers.begin();
while (ri != _deferred_pointers.end()) {
int object_id = (*ri).first;
const vector_int &children = (*ri).second;
ObjectPointers::iterator oi;
oi = _object_pointers.begin();
while (oi != _object_pointers.end()) {
int object_id = (*oi).first;
const vector_int &pointer_ids = (*oi).second;
CreatedObjs::iterator ci = _created_objs.find(object_id);
nassertr(ci != _created_objs.end(), false);
CreatedObj &created_obj = (*ci).second;
TypedWritable *object_ptr = created_obj._ptr;
// Now make sure we have all of the pointers this object is
// waiting for. If any of the pointers has not yet been read
// in, we can't resolve this object--we can't do anything for a
// given object until we have *all* outstanding pointers for
// that object.
bool is_complete = true;
vector_typedWritable references;
vector_int::const_iterator pi;
for (pi = children.begin(); pi != children.end() && is_complete; ++pi) {
int child_id = (*pi);
if (child_id == 0) {
// A NULL pointer is a NULL pointer.
references.push_back((TypedWritable *)NULL);
} else {
// See if we have the pointer available now.
CreatedObjs::const_iterator oi = _created_objs.find(child_id);
if (oi == _created_objs.end()) {
// No, too bad.
is_complete = false;
} else {
const CreatedObj &child_obj = (*oi).second;
if (child_obj._change_this != NULL) {
// It's been created, but the pointer might still change.
is_complete = false;
} else {
// Yes, it's ready.
references.push_back(child_obj._ptr);
}
}
}
}
if (is_complete) {
// Okay, here's the complete list of pointers for you!
int num_completed = object_ptr->complete_pointers(&references[0], this);
if (num_completed != (int)references.size()) {
bam_cat.warning()
<< object_ptr->get_type() << " completed " << num_completed
<< " of " << references.size() << " pointers.\n";
}
if (resolve_object_pointers(object_ptr, pointer_ids)) {
// Now remove this object 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.
Requests::iterator old = ri;
++ri;
_deferred_pointers.erase(old);
ObjectPointers::iterator old = oi;
++oi;
_object_pointers.erase(old);
// Does the pointer need to change?
if (created_obj._change_this != NULL) {
@ -300,12 +256,36 @@ resolve() {
} else {
// Couldn't complete this object yet; it'll wait for next time.
++ri;
++oi;
all_completed = false;
}
}
} 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) {
finalize();
} else {
@ -314,11 +294,11 @@ resolve() {
// which some objects might legitimately be uncompleted after
// calling resolve(), but for now we expect resolve() to always
// succeed.
Requests::const_iterator ri;
for (ri = _deferred_pointers.begin();
ri != _deferred_pointers.end();
++ri) {
int object_id = (*ri).first;
ObjectPointers::const_iterator oi;
for (oi = _object_pointers.begin();
oi != _object_pointers.end();
++oi) {
int object_id = (*oi).first;
CreatedObjs::iterator ci = _created_objs.find(object_id);
nassertr(ci != _created_objs.end(), false);
CreatedObj &created_obj = (*ci).second;
@ -435,32 +415,20 @@ read_handle(DatagramIterator &scan) {
// object properly.
////////////////////////////////////////////////////////////////////
void BamReader::
read_pointer(DatagramIterator &scan, TypedWritable *for_whom) {
read_pointer(DatagramIterator &scan) {
nassertv(_now_creating != _created_objs.end());
int requestor_id = (*_now_creating).first;
/*
On reflection, we'll let this go undetected for now. Maybe we
should remove the this pointer from read_pointer() altogether.
#ifndef NDEBUG
// A bit of sanity checking here: we look up the object ID, and
// assign the "this" pointer into the record if it's not there
// already. Then we can verify the "this" pointer later.
CreatedObj &created_obj = (*_now_creating).second;
if (created_obj._ptr == (TypedWritable *)NULL) {
created_obj._ptr = for_whom;
} else {
// We've previously assigned this pointer, and we should have
// assigned it to the same this pointer we have now.
nassertv(created_obj._ptr == for_whom);
}
#endif // NDEBUG
*/
// Read the object ID, and associate it with the requesting object.
int object_id = scan.get_uint16();
_deferred_pointers[requestor_id].push_back(object_id);
if (_reading_cycler == (PipelineCyclerBase *)NULL) {
// This is not being read within a read_cdata() call.
_object_pointers[requestor_id].push_back(object_id);
} else {
// This *is* being read within a read_cdata() call.
_cycler_pointers[_reading_cycler].push_back(object_id);
}
// If the object ID is zero (which indicates a NULL pointer), we
// don't have to do anything else.
@ -482,9 +450,9 @@ read_pointer(DatagramIterator &scan, TypedWritable *for_whom) {
// read_pointer() count times.
////////////////////////////////////////////////////////////////////
void BamReader::
read_pointers(DatagramIterator &scan, TypedWritable *for_whom, int count) {
read_pointers(DatagramIterator &scan, int count) {
for (int i = 0; i < count; i++) {
read_pointer(scan, for_whom);
read_pointer(scan);
}
}
@ -501,6 +469,25 @@ skip_pointer(DatagramIterator &scan) {
scan.get_uint16();
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::read_cdata
// Access: Public
// Description: Reads in the indicated CycleData object. This should
// be used by classes that store some or all of their
// data within a CycleData subclass, in support of
// pipelining. This will call the virtual
// CycleData::fillin() method to do the actual reading.
////////////////////////////////////////////////////////////////////
void BamReader::
read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler) {
PipelineCyclerBase *old_cycler = _reading_cycler;
_reading_cycler = &cycler;
CycleData *cdata = cycler.write();
cdata->fillin(scan, this);
cycler.release_write(cdata);
_reading_cycler = old_cycler;
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::register_finalize
// Access: Public
@ -739,11 +726,11 @@ p_read_object() {
if (created_obj._change_this != NULL) {
// If the pointer is scheduled to change after
// complete_pointers(), but we have no entry in
// _deferred_pointers for this object (and hence no plan to call
// _object_pointers for this object (and hence no plan to call
// complete_pointers()), then just change the pointer
// immediately.
Requests::const_iterator ri = _deferred_pointers.find(object_id);
if (ri == _deferred_pointers.end()) {
ObjectPointers::const_iterator ri = _object_pointers.find(object_id);
if (ri == _object_pointers.end()) {
object = created_obj._change_this(object, this);
created_obj._ptr = object;
created_obj._change_this = NULL;
@ -772,6 +759,133 @@ p_read_object() {
return object_id;
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::resolve_object_pointers
// Access: Private
// Description: Checks whether all of the pointers a particular
// object is waiting for have been filled in yet. If
// they have, calls complete_pointers() on the object
// and returns true; otherwise, returns false.
////////////////////////////////////////////////////////////////////
bool BamReader::
resolve_object_pointers(TypedWritable *object, const vector_int &pointer_ids) {
// Now make sure we have all of the pointers this object is
// waiting for. If any of the pointers has not yet been read
// in, we can't resolve this object--we can't do anything for a
// given object until we have *all* outstanding pointers for
// that object.
bool is_complete = true;
vector_typedWritable references;
vector_int::const_iterator pi;
for (pi = pointer_ids.begin(); pi != pointer_ids.end() && is_complete; ++pi) {
int child_id = (*pi);
if (child_id == 0) {
// A NULL pointer is a NULL pointer.
references.push_back((TypedWritable *)NULL);
} else {
// See if we have the pointer available now.
CreatedObjs::const_iterator oi = _created_objs.find(child_id);
if (oi == _created_objs.end()) {
// No, too bad.
is_complete = false;
} else {
const CreatedObj &child_obj = (*oi).second;
if (child_obj._change_this != NULL) {
// It's been created, but the pointer might still change.
is_complete = false;
} else {
// Yes, it's ready.
references.push_back(child_obj._ptr);
}
}
}
}
if (is_complete) {
// Okay, here's the complete list of pointers for you!
int num_completed = object->complete_pointers(&references[0], this);
if (num_completed != (int)references.size()) {
bam_cat.warning()
<< object->get_type() << " completed " << num_completed
<< " of " << references.size() << " pointers.\n";
}
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::resolve_cycler_pointers
// Access: Private
// Description: Checks whether all of the pointers a particular
// PipelineCycler is waiting for have been filled in
// yet. If they have, calls complete_pointers() on the
// cycler and returns true; otherwise, returns false.
////////////////////////////////////////////////////////////////////
bool BamReader::
resolve_cycler_pointers(PipelineCyclerBase *cycler,
const vector_int &pointer_ids) {
// Now make sure we have all of the pointers this cycler is
// waiting for. If any of the pointers has not yet been read
// in, we can't resolve this cycler--we can't do anything for a
// given cycler until we have *all* outstanding pointers for
// that cycler.
bool is_complete = true;
vector_typedWritable references;
vector_int::const_iterator pi;
for (pi = pointer_ids.begin(); pi != pointer_ids.end() && is_complete; ++pi) {
int child_id = (*pi);
if (child_id == 0) {
// A NULL pointer is a NULL pointer.
references.push_back((TypedWritable *)NULL);
} else {
// See if we have the pointer available now.
CreatedObjs::const_iterator oi = _created_objs.find(child_id);
if (oi == _created_objs.end()) {
// No, too bad.
is_complete = false;
} else {
const CreatedObj &child_obj = (*oi).second;
if (child_obj._change_this != NULL) {
// It's been created, but the pointer might still change.
is_complete = false;
} else {
// Yes, it's ready.
references.push_back(child_obj._ptr);
}
}
}
}
if (is_complete) {
// Okay, here's the complete list of pointers for you!
CycleData *cdata = cycler->write();
int num_completed = cdata->complete_pointers(&references[0], this);
cycler->release_write(cdata);
if (num_completed != (int)references.size()) {
bam_cat.warning()
<< "CycleData object completed " << num_completed
<< " of " << references.size() << " pointers.\n";
}
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::finalize
// Access: Private

View File

@ -19,8 +19,8 @@
#ifndef __BAM_READER_
#define __BAM_READER_
#include <pandabase.h>
#include <notify.h>
#include "pandabase.h"
#include "notify.h"
#include "typedWritable.h"
#include "datagramGenerator.h"
@ -33,6 +33,8 @@
#include <algorithm>
class PipelineCyclerBase;
// A handy macro for reading PointerToArrays.
#define READ_PTA(Manager, source, Read_func, array) \
@ -108,10 +110,12 @@ public:
public:
// Functions to support classes that read themselves from the Bam.
void read_pointer(DatagramIterator &scan, TypedWritable *for_whom);
void read_pointers(DatagramIterator &scan, TypedWritable *for_whom, int count);
void read_pointer(DatagramIterator &scan);
void read_pointers(DatagramIterator &scan, int count);
void skip_pointer(DatagramIterator &scan);
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler);
void register_finalize(TypedWritable *whom);
typedef TypedWritable *(*ChangeThisFunc)(TypedWritable *object, BamReader *manager);
@ -132,6 +136,8 @@ private:
private:
int p_read_object();
bool resolve_object_pointers(TypedWritable *object, const vector_int &pointer_ids);
bool resolve_cycler_pointers(PipelineCyclerBase *cycler, const vector_int &pointer_ids);
void finalize();
private:
@ -158,12 +164,20 @@ private:
// during recursion. We need this so we can associate
// read_pointer() calls with the proper objects.
CreatedObjs::iterator _now_creating;
// This is the pointer to the current PipelineCycler we are reading,
// if we are within a read_cdata() call.
PipelineCyclerBase *_reading_cycler;
// This records all the objects that still need their pointers
// completed, along with the object ID's of the pointers they need,
// in the order in which read_pointer() was called.
typedef pmap<int, vector_int> Requests;
Requests _deferred_pointers;
// in the order in which read_pointer() was called, so that we may
// call the appropriate complete_pointers() later.
typedef pmap<int, vector_int> ObjectPointers;
ObjectPointers _object_pointers;
// Ditto, for the PiplineCycler objects.
typedef pmap<PipelineCyclerBase *, vector_int> CyclerPointers;
CyclerPointers _cycler_pointers;
// This is the number of extra objects that must still be read (and
// saved in the _created_objs map) before returning from

View File

@ -162,6 +162,19 @@ write_object(const TypedWritable *object) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::has_object
// Access: Public
// Description: Returns true if the object has previously been
// written (or at least requested to be written) to the
// bam file, or false if we've never heard of it before.
////////////////////////////////////////////////////////////////////
bool BamWriter::
has_object(const TypedWritable *object) const {
StateMap::const_iterator si = _state_map.find(object);
return (si != _state_map.end());
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::write_pointer
// Access: Public
@ -199,6 +212,23 @@ write_pointer(Datagram &packet, const TypedWritable *object) {
}
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::write_cdata
// Access: Public
// Description: Writes out the indicated CycleData object. This
// should be used by classes that store some or all of
// their data within a CycleData subclass, in support of
// pipelining. This will call the virtual
// CycleData::write_datagram() method to do the actual
// writing.
////////////////////////////////////////////////////////////////////
void BamWriter::
write_cdata(Datagram &packet, const PipelineCyclerBase &cycler) {
const CycleData *cdata = cycler.read();
cdata->write_datagram(this, packet);
cycler.release_read(cdata);
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::register_pta
// Access: Public

View File

@ -19,13 +19,15 @@
#ifndef __BAM_WRITER_
#define __BAM_WRITER_
#include <pandabase.h>
#include <notify.h>
#include "pandabase.h"
#include "notify.h"
#include "typedWritable.h"
#include "datagramSink.h"
#include "pdeque.h"
class PipelineCyclerBase;
// A handy macro for writing PointerToArrays.
#define WRITE_PTA(Manager, dest, Write_func, array) \
if (!Manager->register_pta(dest, array.p())) \
@ -78,14 +80,18 @@ public:
bool init();
bool write_object(const TypedWritable *obj);
bool has_object(const TypedWritable *obj) const;
public:
// Functions to support classes that write themselves to the Bam.
void write_pointer(Datagram &packet, const TypedWritable *dest);
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler);
bool register_pta(Datagram &packet, const void *ptr);
void write_handle(Datagram &packet, TypeHandle type);
private:
int enqueue_object(const TypedWritable *object);

View File

@ -27,3 +27,38 @@
CycleData::
~CycleData() {
}
////////////////////////////////////////////////////////////////////
// Function: CycleData::write_datagram
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
void CycleData::
write_datagram(BamWriter *, Datagram &) const {
}
////////////////////////////////////////////////////////////////////
// Function: CycleData::complete_pointers
// Access: Public, Virtual
// Description: Receives an array of pointers, one for each time
// manager->read_pointer() was called in fillin().
// Returns the number of pointers processed.
////////////////////////////////////////////////////////////////////
int CycleData::
complete_pointers(TypedWritable **, BamReader *) {
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: CycleData::fillin
// Access: Public, Virtual
// Description: This internal function is intended to be called by
// each class's make_from_bam() method to read in all of
// the relevant data from the BamFile for the new
// object.
////////////////////////////////////////////////////////////////////
void CycleData::
fillin(DatagramIterator &, BamReader *) {
}

View File

@ -23,6 +23,12 @@
#include "referenceCount.h"
class BamWriter;
class BamReader;
class TypedWritable;
class Datagram;
class DatagramIterator;
////////////////////////////////////////////////////////////////////
// Class : CycleData
// Description : A single page of data maintained by a PipelineCycler.
@ -51,6 +57,10 @@ public:
virtual ~CycleData();
virtual CycleData *make_copy() const=0;
virtual void write_datagram(BamWriter *, Datagram &) const;
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager);
virtual void fillin(DatagramIterator &scan, BamReader *manager);
};
#include "cycleData.I"

View File

@ -28,6 +28,7 @@ CycleDataReader(const PipelineCycler<CycleDataType> &cycler) :
_cycler(cycler)
{
_pointer = _cycler.read();
_write_pointer = (CycleDataType *)NULL;
}
////////////////////////////////////////////////////////////////////
@ -39,8 +40,13 @@ template<class CycleDataType>
INLINE CycleDataReader<CycleDataType>::
CycleDataReader(const CycleDataReader<CycleDataType> &copy) :
_cycler(copy._cycler),
_pointer(copy._pointer)
_pointer(copy._pointer),
_write_pointer(copy._write_pointer)
{
nassertv(_pointer != (const CycleDataType *)NULL);
// We cannot copy-construct a CycleDataReader that has elevated
// itself to a write pointer.
nassertv(_write_pointer == (const CycleDataType *)NULL);
_cycler.increment_read(_pointer);
}
@ -52,7 +58,14 @@ CycleDataReader(const CycleDataReader<CycleDataType> &copy) :
template<class CycleDataType>
INLINE CycleDataReader<CycleDataType>::
~CycleDataReader() {
_cycler.release_read(_pointer);
if (_write_pointer != (CycleDataType *)NULL) {
// If the _write_pointer is non-NULL, then someone called
// elevate_to_write() at some point, and we now actually hold a
// write pointer, not a read pointer.
((PipelineCycler<CycleDataType> &)_cycler).release_write(_write_pointer);
} else if (_pointer != (CycleDataType *)NULL) {
_cycler.release_read(_pointer);
}
}
////////////////////////////////////////////////////////////////////
@ -64,5 +77,58 @@ INLINE CycleDataReader<CycleDataType>::
template<class CycleDataType>
INLINE const CycleDataType *CycleDataReader<CycleDataType>::
operator -> () const {
nassertr(_pointer != (const CycleDataType *)NULL, _cycler.cheat());
return _pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataReader::Typecast pointer
// Access: Public
// Description: This allows the CycleDataReader to be passed to any
// function that expects a const CycleDataType pointer.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataReader<CycleDataType>::
operator const CycleDataType * () const {
nassertr(_pointer != (const CycleDataType *)NULL, _cycler.cheat());
return _pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataReader::take_pointer
// Access: Public
// Description: This is intended to be called only from
// CycleDataWriter when it elevates the pointer from
// read to write status. This function returns the
// reader's pointer and relinquishes ownership of the
// pointer, rendering the reader invalid for future
// reads.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *CycleDataReader<CycleDataType>::
take_pointer() {
const CycleDataType *pointer = _pointer;
_pointer = (CycleDataType *)NULL;
_write_pointer = (CycleDataType *)NULL;
nassertr(_pointer != (const CycleDataType *)NULL, _cycler.cheat());
return pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataReader::elevate_to_write
// Access: Public
// Description: Call this to permanently elevate the readable pointer
// to a writable pointer. This returns a writable
// pointer; subsequent calls to the same function will
// trivially return the same writable pointer.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataType *CycleDataReader<CycleDataType>::
elevate_to_write(PipelineCycler<CycleDataType> &cycler) {
nassertr(&cycler = &_cycler, cycler.cheat());
if (_write_pointer == (CycleDataType *)NULL) {
_write_pointer = cycler.elevate_read(_pointer);
_pointer = _write_pointer;
}
return _write_pointer;
}

View File

@ -45,10 +45,15 @@ public:
INLINE ~CycleDataReader();
INLINE const CycleDataType *operator -> () const;
INLINE operator const CycleDataType * () const;
INLINE const CycleDataType *take_pointer();
INLINE CycleDataType *elevate_to_write(PipelineCycler<CycleDataType> &cycler);
private:
const PipelineCycler<CycleDataType> &_cycler;
const CycleDataType *_pointer;
CycleDataType *_write_pointer;
};
#include "cycleDataReader.I"

View File

@ -31,17 +31,39 @@ CycleDataWriter(PipelineCycler<CycleDataType> &cycler) :
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataWriter::Copy Constructor
// Function: CycleDataWriter::Constructor
// Access: Public
// Description:
// Description: This is a lot like a copy constructor, in that the
// new CycleDataWriter object gets a handle to the same
// pointer held by the old CycleDataWriter object.
// However, since only one write pointer may be active
// at a time, this invalidates the old object.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
CycleDataWriter(const CycleDataWriter<CycleDataType> &copy) :
_cycler(copy._cycler),
_pointer(copy._pointer)
CycleDataWriter(PipelineCycler<CycleDataType> &cycler,
CycleDataWriter<CycleDataType> &take_from) :
_cycler(cycler),
_pointer(take_from._pointer)
{
_cycler.increment_write(_pointer);
take_from._pointer = (CycleDataType *)NULL;
nassertv(_pointer != (CycleDataType *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataWriter::Constructor
// Access: Public
// Description: This flavor of the constructor elevates the pointer
// from the CycleDataReader from a read to a write
// pointer (and invalidates the reader).
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
CycleDataWriter(PipelineCycler<CycleDataType> &cycler,
CycleDataReader<CycleDataType> &take_from) :
_cycler(cycler)
{
_pointer = _cycler.elevate_read(take_from.take_pointer());
}
////////////////////////////////////////////////////////////////////
@ -52,7 +74,9 @@ CycleDataWriter(const CycleDataWriter<CycleDataType> &copy) :
template<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
~CycleDataWriter() {
_cycler.release_write(_pointer);
if (_pointer != (CycleDataType *)NULL) {
_cycler.release_write(_pointer);
}
}
////////////////////////////////////////////////////////////////////
@ -64,6 +88,7 @@ INLINE CycleDataWriter<CycleDataType>::
template<class CycleDataType>
INLINE CycleDataType *CycleDataWriter<CycleDataType>::
operator -> () {
nassertr(_pointer != (CycleDataType *)NULL, _cycler.cheat());
return _pointer;
}
@ -76,5 +101,19 @@ operator -> () {
template<class CycleDataType>
INLINE const CycleDataType *CycleDataWriter<CycleDataType>::
operator -> () const {
nassertr(_pointer != (CycleDataType *)NULL, _cycler.cheat());
return _pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataWriter::Typecast pointer
// Access: Public
// Description: This allows the CycleDataWriter to be passed to any
// function that expects a CycleDataType pointer.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
operator CycleDataType * () {
nassertr(_pointer != (CycleDataType *)NULL, _cycler.cheat());
return _pointer;
}

View File

@ -40,13 +40,16 @@ template<class CycleDataType>
class CycleDataWriter {
public:
INLINE CycleDataWriter(PipelineCycler<CycleDataType> &cycler);
INLINE CycleDataWriter(const CycleDataWriter<CycleDataType> &copy);
INLINE CycleDataWriter(PipelineCycler<CycleDataType> &cycler, CycleDataWriter<CycleDataType> &take_from);
INLINE CycleDataWriter(PipelineCycler<CycleDataType> &cycler, CycleDataReader<CycleDataType> &take_from);
INLINE ~CycleDataWriter();
INLINE CycleDataType *operator -> ();
INLINE const CycleDataType *operator -> () const;
INLINE operator CycleDataType * ();
private:
PipelineCycler<CycleDataType> &_cycler;
CycleDataType *_pointer;

View File

@ -33,6 +33,29 @@ PipelineCycler(Pipeline *pipeline) :
{
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::Copy Constructor (sanity-check)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE PipelineCycler<CycleDataType>::
PipelineCycler(const PipelineCycler<CycleDataType> &copy) :
PipelineCyclerBase(copy)
{
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::Copy Assignment (sanity-check)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE void PipelineCycler<CycleDataType>::
operator = (const PipelineCycler<CycleDataType> &copy) {
PipelineCyclerBase::operator = (copy);
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::read (sanity-check)
// Access: Public
@ -55,6 +78,17 @@ write() {
return (CycleDataType *)PipelineCyclerBase::write();
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::elevate_read (sanity-check)
// Access: Public
// Description: See PipelineCyclerBase::elevate_read().
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataType *PipelineCycler<CycleDataType>::
elevate_read(const CycleDataType *pointer) {
return (CycleDataType *)PipelineCyclerBase::elevate_read(pointer);
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::write_stage (sanity-check)
// Access: Public
@ -66,6 +100,22 @@ write_stage(int n) {
return (CycleDataType *)PipelineCyclerBase::write_stage(n);
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::cheat (sanity-check)
// Access: Public
// Description: Returns a pointer without counting it. This is only
// intended for use as the return value for certain
// nassertr() functions, so the application can recover
// after a failure to manage the read and write pointers
// correctly. You should never call this function
// directly.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataType *PipelineCycler<CycleDataType>::
cheat() const {
return (CycleDataType *)PipelineCyclerBase::cheat();
}
#else // !DO_PIPELINING
// The following implementations are provided for when pipelining is
// not compiled in. They are trivial functions that do as little as
@ -83,6 +133,31 @@ PipelineCycler(Pipeline *pipeline) :
{
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::Copy Constructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE PipelineCycler<CycleDataType>::
PipelineCycler(const PipelineCycler<CycleDataType> &copy) :
PipelineCyclerBase(copy),
_data(copy._data)
{
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::Copy Assignment (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE void PipelineCycler<CycleDataType>::
operator = (const PipelineCycler<CycleDataType> &copy) {
PipelineCyclerBase::operator = (copy);
_data = copy._data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::read (trivial)
// Access: Public
@ -105,6 +180,17 @@ write() {
return &_data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::elevate_read (trivial)
// Access: Public
// Description: See PipelineCyclerBase::elevate_read().
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataType *PipelineCycler<CycleDataType>::
elevate_read(const CycleDataType *) {
return &_data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::write_stage (trivial)
// Access: Public
@ -116,5 +202,21 @@ write_stage(int) {
return &_data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::cheat (trivial)
// Access: Public
// Description: Returns a pointer without counting it. This is only
// intended for use as the return value for certain
// nassertr() functions, so the application can recover
// after a failure to manage the read and write pointers
// correctly. You should never call this function
// directly.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataType *PipelineCycler<CycleDataType>::
cheat() const {
return &_data;
}
#endif // DO_PIPELINING

View File

@ -53,11 +53,16 @@ template<class CycleDataType>
class PipelineCycler : public PipelineCyclerBase {
public:
INLINE PipelineCycler(Pipeline *pipeline = NULL);
INLINE PipelineCycler(const PipelineCycler<CycleDataType> &copy);
INLINE void operator = (const PipelineCycler<CycleDataType> &copy);
INLINE const CycleDataType *read() const;
INLINE CycleDataType *write();
INLINE CycleDataType *elevate_read(const CycleDataType *pointer);
INLINE CycleDataType *write_stage(int n);
INLINE CycleDataType *cheat() const;
#ifndef DO_PIPELINING
private:
// If we are *not* compiling in support for pipelining, we just

View File

@ -21,6 +21,61 @@
// The following implementations are to support compiled-in pipeline
// sanity checks.
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::Constructor (sanity-check)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PipelineCyclerBase::
PipelineCyclerBase(CycleData *initial_data, Pipeline *pipeline) :
_data(initial_data),
_pipeline(pipeline),
_read_count(0),
_write_count(0),
_stage_count(0)
{
if (_pipeline == (Pipeline *)NULL) {
_pipeline = Pipeline::get_render_pipeline();
}
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::Copy Constructor (sanity-check)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PipelineCyclerBase::
PipelineCyclerBase(const PipelineCyclerBase &copy) :
_data(copy._data->make_copy()),
_pipeline(copy._pipeline),
_read_count(0),
_write_count(0),
_stage_count(0)
{
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::Copy Assignment (sanity-check)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerBase::
operator = (const PipelineCyclerBase &copy) {
nassertv(_read_count == 0 && _write_count == 0 && _stage_count == 0);
_data = copy._data->make_copy();
_pipeline = copy._pipeline;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::Destructor (sanity-check)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PipelineCyclerBase::
~PipelineCyclerBase() {
nassertv(_read_count == 0 && _write_count == 0 && _stage_count == 0);
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::read (sanity-check)
// Access: Public
@ -28,12 +83,16 @@
// data for the current stage of the pipeline as seen by
// this thread. This pointer should eventually be
// released by calling release_read().
//
// There should be no outstanding write pointers on the
// data when this function is called.
////////////////////////////////////////////////////////////////////
INLINE const CycleData *PipelineCyclerBase::
read() const {
// This function isn't truly const, but it doesn't change the data
// in any meaningful way, so we pretend it is.
((PipelineCyclerBase *)this)->_read_count++;
nassertr(_write_count == 0, _data);
return _data;
}
@ -78,25 +137,33 @@ release_read(const CycleData *pointer) const {
// the data will be propagate to all later stages of the
// pipeline. This pointer should eventually be released
// by calling release_write().
//
// There may only be one outstanding write pointer on a
// given stage at a time, and if there is a write
// pointer there may be no read pointers on the same
// stage (but see elevate_read).
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerBase::
write() {
_write_count++;
nassertr(_read_count == 0, _data);
nassertr(_write_count == 1, _data);
return _data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::increment_write (sanity-check)
// Function: PipelineCyclerBase::elevate_read (sanity-check)
// Access: Public
// Description: Increments the count on a pointer previously
// retrieved by write(); now the pointer will need to be
// released twice.
// Description: Elevates a currently-held read pointer into a write
// pointer. This may or may not change the value of the
// pointer. It is only valid to do this if this is the
// only currently-outstanding read pointer on the
// current stage.
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerBase::
increment_write(CycleData *pointer) {
nassertv(pointer == _data);
nassertv(_write_count > 0);
_write_count++;
INLINE CycleData *PipelineCyclerBase::
elevate_read(const CycleData *pointer) {
release_read(pointer);
return write();
}
////////////////////////////////////////////////////////////////////
@ -166,13 +233,43 @@ release_write_stage(int n, CycleData *pointer) {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::Destructor (sanity-check)
// Function: PipelineCyclerBase::cheat (sanity-check)
// Access: Public
// Description:
// Description: Returns a pointer without counting it. This is only
// intended for use as the return value for certain
// nassertr() functions, so the application can recover
// after a failure to manage the read and write pointers
// correctly. You should never call this function
// directly.
////////////////////////////////////////////////////////////////////
INLINE PipelineCyclerBase::
~PipelineCyclerBase() {
nassertv(_read_count == 0 && _write_count == 0 && _stage_count == 0);
INLINE CycleData *PipelineCyclerBase::
cheat() const {
return _data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::get_read_count (sanity-check)
// Access: Public
// Description: Returns the number of handles currently outstanding
// to read the current stage of the data. This should
// only be used for debugging purposes.
////////////////////////////////////////////////////////////////////
INLINE int PipelineCyclerBase::
get_read_count() const {
return _read_count;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::get_write_count (sanity-check)
// Access: Public
// Description: Returns the number of handles currently outstanding
// to read the current stage of the data. This will
// normally only be either 0 or 1. This should only be
// used for debugging purposes.
////////////////////////////////////////////////////////////////////
INLINE int PipelineCyclerBase::
get_write_count() const {
return _write_count;
}
#else // !DO_PIPELINING
@ -180,6 +277,43 @@ INLINE PipelineCyclerBase::
// not compiled in. They are trivial functions that do as little as
// possible.
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::Constructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PipelineCyclerBase::
PipelineCyclerBase(CycleData *initial_data, Pipeline *) {
// In the trivial implementation, a derived class (the
// PipelineCycler template class) stores the CycleData object
// directly within itself, and since we have no data members or
// virtual functions, we get away with assuming the pointer is the
// same as the 'this' pointer.
// If this turns out not to be true on a particular platform, we
// will have to store the pointer in this class, for a little bit of
// extra overhead.
nassertv(initial_data == (CycleData *)this);
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::Copy Constructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PipelineCyclerBase::
PipelineCyclerBase(const PipelineCyclerBase &) {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::Copy Assignment (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerBase::
operator = (const PipelineCyclerBase &) {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::Destructor (trivial)
// Access: Public
@ -233,6 +367,11 @@ release_read(const CycleData *) const {
// the data will be propagate to all later stages of the
// pipeline. This pointer should eventually be released
// by calling release_write().
//
// There may only be one outstanding write pointer on a
// given stage at a time, and if there is a write
// pointer there may be no read pointers on the same
// stage (but see elevate_read).
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerBase::
write() {
@ -240,14 +379,17 @@ write() {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::increment_write (trivial)
// Function: PipelineCyclerBase::elevate_read (trivial)
// Access: Public
// Description: Increments the count on a pointer previously
// retrieved by write(); now the pointer will need to be
// released twice.
// Description: Elevates a currently-held read pointer into a write
// pointer. This may or may not change the value of the
// pointer. It is only valid to do this if this is the
// only currently-outstanding read pointer on the
// current stage.
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerBase::
increment_write(CycleData *) {
INLINE CycleData *PipelineCyclerBase::
elevate_read(const CycleData *) {
return (CycleData *)this;
}
////////////////////////////////////////////////////////////////////
@ -307,5 +449,45 @@ INLINE void PipelineCyclerBase::
release_write_stage(int, CycleData *) {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::cheat (trivial)
// Access: Public
// Description: Returns a pointer without counting it. This is only
// intended for use as the return value for certain
// nassertr() functions, so the application can recover
// after a failure to manage the read and write pointers
// correctly. You should never call this function
// directly.
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerBase::
cheat() const {
return (CycleData *)this;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::get_read_count (trivial)
// Access: Public
// Description: Returns the number of handles currently outstanding
// to read the current stage of the data. This should
// only be used for debugging purposes.
////////////////////////////////////////////////////////////////////
INLINE int PipelineCyclerBase::
get_read_count() const {
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::get_write_count (trivial)
// Access: Public
// Description: Returns the number of handles currently outstanding
// to read the current stage of the data. This will
// normally only be either 0 or 1. This should only be
// used for debugging purposes.
////////////////////////////////////////////////////////////////////
INLINE int PipelineCyclerBase::
get_write_count() const {
return 0;
}
#endif // DO_PIPELINING

View File

@ -23,47 +23,10 @@
// The following implementations are to support compiled-in pipeline
// sanity checks.
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::Constructor (sanity-check)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
PipelineCyclerBase::
PipelineCyclerBase(CycleData *initial_data, Pipeline *pipeline) :
_data(initial_data),
_pipeline(pipeline),
_read_count(0),
_write_count(0),
_stage_count(0)
{
if (_pipeline == (Pipeline *)NULL) {
_pipeline = Pipeline::get_render_pipeline();
}
}
#else // !DO_PIPELINING
// The following implementations are provided for when pipelining is
// not compiled in. They are trivial functions that do as little as
// possible.
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::Constructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
PipelineCyclerBase::
PipelineCyclerBase(CycleData *initial_data, Pipeline *) {
// In the trivial implementation, a derived class (the
// PipelineCycler template class) stores the CycleData object
// directly within itself, and since we have no data members or
// virtual functions, we get away with assuming the pointer is the
// same as the 'this' pointer.
// If this turns out not to be true on a particular platform, we
// will have to store the pointer in this class, for a little bit of
// extra overhead.
nassertv(initial_data == (CycleData *)this);
}
#endif

View File

@ -32,7 +32,9 @@
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA PipelineCyclerBase {
public:
PipelineCyclerBase(CycleData *initial_data, Pipeline *pipeline = NULL);
INLINE PipelineCyclerBase(CycleData *initial_data, Pipeline *pipeline = NULL);
INLINE PipelineCyclerBase(const PipelineCyclerBase &copy);
INLINE void operator = (const PipelineCyclerBase &copy);
INLINE ~PipelineCyclerBase();
INLINE const CycleData *read() const;
@ -40,7 +42,7 @@ public:
INLINE void release_read(const CycleData *pointer) const;
INLINE CycleData *write();
INLINE void increment_write(CycleData *pointer);
INLINE CycleData *elevate_read(const CycleData *pointer);
INLINE void release_write(CycleData *pointer);
INLINE int get_num_stages();
@ -48,6 +50,10 @@ public:
INLINE CycleData *write_stage(int n);
INLINE void release_write_stage(int n, CycleData *pointer);
INLINE CycleData *cheat() const;
INLINE int get_read_count() const;
INLINE int get_write_count() const;
#ifdef DO_PIPELINING
// This private data is only stored here if we have pipelining
// compiled in. Actually, this particular data is only used for

View File

@ -77,8 +77,8 @@ fillin(Person* me, DatagramIterator& scan, BamReader* manager)
{
_name = scan.get_string();
myGender = scan.get_uint8();
manager->read_pointer(scan, this);
manager->read_pointer(scan, this);
manager->read_pointer(scan);
manager->read_pointer(scan);
}
int Person::
@ -122,8 +122,8 @@ void Parent::
fillin(Parent* me, DatagramIterator& scan, BamReader* manager)
{
Person::fillin(me, scan, manager);
manager->read_pointer(scan, this);
manager->read_pointer(scan, this);
manager->read_pointer(scan);
manager->read_pointer(scan);
}
int Parent::
@ -182,8 +182,8 @@ void Child::
fillin(Child* me, DatagramIterator& scan, BamReader* manager)
{
Person::fillin(me, scan, manager);
manager->read_pointer(scan, this);
manager->read_pointer(scan, this);
manager->read_pointer(scan);
manager->read_pointer(scan);
}
int Child::

View File

@ -189,5 +189,5 @@ make_MaterialTransition(const FactoryParams &params) {
void MaterialTransition::
fillin(DatagramIterator& scan, BamReader* manager) {
OnOffTransition::fillin(scan, manager);
manager->read_pointer(scan, this);
manager->read_pointer(scan);
}

View File

@ -190,5 +190,5 @@ make_TextureTransition(const FactoryParams &params) {
void TextureTransition::
fillin(DatagramIterator& scan, BamReader* manager) {
OnOffTransition::fillin(scan, manager);
manager->read_pointer(scan, this);
manager->read_pointer(scan);
}

View File

@ -507,7 +507,7 @@ fillin(DatagramIterator& scan, BamReader* manager)
_num_geoms = scan.get_uint16();
for(int i = 0; i < _num_geoms; i++)
{
manager->read_pointer(scan, this);
manager->read_pointer(scan);
}
}

View File

@ -628,10 +628,10 @@ fillin(DatagramIterator &scan, BamReader *manager) {
_dest_filename = FilenameUnifier::get_bam_filename(scan.get_string());
_num_textures = scan.get_uint32();
manager->read_pointers(scan, this, _num_textures);
manager->read_pointers(scan, _num_textures);
_explicitly_assigned_groups.fillin(scan, manager);
manager->read_pointer(scan, this); // _default_group
manager->read_pointer(scan); // _default_group
_is_surprise = scan.get_bool();
_is_stale = scan.get_bool();

View File

@ -725,8 +725,8 @@ fillin(DatagramIterator &scan, BamReader *manager) {
}
_num_placements = scan.get_uint32();
manager->read_pointers(scan, this, _num_placements);
manager->read_pointers(scan, _num_placements);
_num_pages = scan.get_uint32();
manager->read_pointers(scan, this, _num_pages);
manager->read_pointers(scan, _num_pages);
}

View File

@ -338,5 +338,5 @@ void PaletteGroups::
fillin(DatagramIterator &scan, BamReader *manager) {
TypedWritable::fillin(scan, manager);
_num_groups = scan.get_int32();
manager->read_pointers(scan, this, _num_groups);
manager->read_pointers(scan, _num_groups);
}

View File

@ -849,9 +849,9 @@ fillin(DatagramIterator &scan, BamReader *manager) {
}
_num_placements = scan.get_uint32();
manager->read_pointers(scan, this, _num_placements);
manager->read_pointers(scan, _num_placements);
manager->read_pointer(scan, this); // _page
manager->read_pointer(scan); // _page
_index = scan.get_uint32();
_basename = scan.get_string();

View File

@ -347,9 +347,9 @@ fillin(DatagramIterator &scan, BamReader *manager) {
TypedWritable::fillin(scan, manager);
set_name(scan.get_string());
manager->read_pointer(scan, this); // _group
manager->read_pointer(scan); // _group
_properties.fillin(scan, manager);
_num_images = scan.get_uint32();
manager->read_pointers(scan, this, _num_images);
manager->read_pointers(scan, _num_images);
}

View File

@ -1018,18 +1018,18 @@ fillin(DatagramIterator &scan, BamReader *manager) {
_remap_char_uv = (RemapUV)scan.get_int32();
}
manager->read_pointer(scan, this); // _color_type
manager->read_pointer(scan, this); // _alpha_type
manager->read_pointer(scan, this); // _shadow_color_type
manager->read_pointer(scan, this); // _shadow_alpha_type
manager->read_pointer(scan); // _color_type
manager->read_pointer(scan); // _alpha_type
manager->read_pointer(scan); // _shadow_color_type
manager->read_pointer(scan); // _shadow_alpha_type
_num_egg_files = scan.get_int32();
manager->read_pointers(scan, this, _num_egg_files);
manager->read_pointers(scan, _num_egg_files);
_num_groups = scan.get_int32();
manager->read_pointers(scan, this, _num_groups);
manager->read_pointers(scan, _num_groups);
_num_textures = scan.get_int32();
manager->read_pointers(scan, this, _num_textures);
manager->read_pointers(scan, _num_textures);
}

View File

@ -237,5 +237,5 @@ make_SourceTextureImage(const FactoryParams &params) {
void SourceTextureImage::
fillin(DatagramIterator &scan, BamReader *manager) {
ImageFile::fillin(scan, manager);
manager->read_pointer(scan, this); // _texture
manager->read_pointer(scan); // _texture
}

View File

@ -1245,10 +1245,10 @@ fillin(DatagramIterator &scan, BamReader *manager) {
_actual_assigned_groups.fillin(scan, manager);
_num_placement = scan.get_uint32();
manager->read_pointers(scan, this, _num_placement * 2);
manager->read_pointers(scan, _num_placement * 2);
_num_sources = scan.get_uint32();
manager->read_pointers(scan, this, _num_sources);
manager->read_pointers(scan, _num_sources);
_num_dests = scan.get_uint32();
manager->read_pointers(scan, this, _num_dests);
manager->read_pointers(scan, _num_dests);
}

View File

@ -1029,12 +1029,12 @@ void TexturePlacement::
fillin(DatagramIterator &scan, BamReader *manager) {
TypedWritable::fillin(scan, manager);
manager->read_pointer(scan, this); // _texture
manager->read_pointer(scan, this); // _group
manager->read_pointer(scan, this); // _image
manager->read_pointer(scan); // _texture
manager->read_pointer(scan); // _group
manager->read_pointer(scan); // _image
if (Palettizer::_read_pi_version >= 2) {
manager->read_pointer(scan, this); // _dest
manager->read_pointer(scan); // _dest
}
_has_uvs = scan.get_bool();
@ -1046,7 +1046,7 @@ fillin(DatagramIterator &scan, BamReader *manager) {
_omit_reason = (OmitReason)scan.get_int32();
_num_references = scan.get_int32();
manager->read_pointers(scan, this, _num_references);
manager->read_pointers(scan, _num_references);
}

View File

@ -681,6 +681,6 @@ fillin(DatagramIterator &scan, BamReader *manager) {
}
_minfilter = (EggTexture::FilterType)scan.get_int32();
_magfilter = (EggTexture::FilterType)scan.get_int32();
manager->read_pointer(scan, this); // _color_type
manager->read_pointer(scan, this); // _alpha_type
manager->read_pointer(scan); // _color_type
manager->read_pointer(scan); // _alpha_type
}

View File

@ -773,13 +773,13 @@ make_TextureReference(const FactoryParams &params) {
void TextureReference::
fillin(DatagramIterator &scan, BamReader *manager) {
TypedWritable::fillin(scan, manager);
manager->read_pointer(scan, this); // _egg_file
manager->read_pointer(scan); // _egg_file
_tex_mat.read_datagram(scan);
_inv_tex_mat.read_datagram(scan);
manager->read_pointer(scan, this); // _source_texture
manager->read_pointer(scan, this); // _placement
manager->read_pointer(scan); // _source_texture
manager->read_pointer(scan); // _placement
_uses_alpha = scan.get_bool();
_any_uvs = scan.get_bool();