mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 09:52:27 -04:00
pgraph flatten
This commit is contained in:
parent
a56e32de31
commit
9c3a3c9c22
@ -118,6 +118,7 @@ pgraphClassRenameDictionary = {
|
||||
'PGEntry' : 'SpPGEntry',
|
||||
'PGWaitBar' : 'SpPGWaitBar',
|
||||
'PartBundleNode' : 'SpPartBundleNode',
|
||||
'SceneGraphReducer' : 'SpSceneGraphReducer',
|
||||
'SequenceNode' : 'SpSequenceNode',
|
||||
'TextNode' : 'SpTextNode',
|
||||
'Trackball' : 'SpTrackball',
|
||||
@ -150,6 +151,7 @@ pgraphClassRenameDictionary = {
|
||||
'QpPGEntry' : 'PGEntry',
|
||||
'QpPGWaitBar' : 'PGWaitBar',
|
||||
'QpPartBundleNode' : 'PartBundleNode',
|
||||
'QpSceneGraphReducer' : 'SceneGraphReducer',
|
||||
'QpSequenceNode' : 'SequenceNode',
|
||||
'QpTextNode' : 'TextNode',
|
||||
'QpTrackball' : 'Trackball',
|
||||
|
@ -216,6 +216,7 @@ class ShowBase:
|
||||
rendering 3-d geometry.
|
||||
"""
|
||||
self.render = NodePath('render')
|
||||
self.render.setTwoSided(0)
|
||||
|
||||
def setupRender2d(self):
|
||||
"""setupRender2d(self)
|
||||
|
@ -1008,7 +1008,6 @@ setup_bucket(BuilderBucket &bucket, PandaNode *parent,
|
||||
break;
|
||||
|
||||
default:
|
||||
bucket.add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_none));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1050,9 +1049,6 @@ setup_bucket(BuilderBucket &bucket, PandaNode *parent,
|
||||
// The primitive is marked with backface culling disabled--we want
|
||||
// to see both sides.
|
||||
bucket.add_attrib(CullFaceAttrib::make(CullFaceAttrib::M_cull_none));
|
||||
|
||||
} else {
|
||||
bucket.add_attrib(CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,11 +19,8 @@
|
||||
#include "qpload_egg_file.h"
|
||||
#include "qpeggLoader.h"
|
||||
#include "config_egg2pg.h"
|
||||
|
||||
/*
|
||||
#include "sceneGraphReducer.h"
|
||||
#include "qpsceneGraphReducer.h"
|
||||
#include "renderRelation.h"
|
||||
*/
|
||||
|
||||
static PT(PandaNode)
|
||||
load_from_loader(qpEggLoader &loader) {
|
||||
@ -37,13 +34,11 @@ load_from_loader(qpEggLoader &loader) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
if (loader._root != (NamedNode *)NULL && egg_flatten) {
|
||||
SceneGraphReducer gr(RenderRelation::get_class_type());
|
||||
if (loader._root != (PandaNode *)NULL && egg_flatten) {
|
||||
qpSceneGraphReducer gr;
|
||||
int num_reduced = gr.flatten(loader._root, egg_flatten_siblings);
|
||||
egg2pg_cat.info() << "Flattened " << num_reduced << " arcs.\n";
|
||||
egg2pg_cat.info() << "Flattened " << num_reduced << " nodes.\n";
|
||||
}
|
||||
*/
|
||||
|
||||
return loader._root;
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
qpfog.I qpfog.h \
|
||||
fogAttrib.I fogAttrib.h \
|
||||
qpgeomNode.I qpgeomNode.h \
|
||||
qpgeomTransformer.I qpgeomTransformer.h \
|
||||
qplensNode.I qplensNode.h \
|
||||
qplodNode.I qplodNode.h \
|
||||
materialAttrib.I materialAttrib.h \
|
||||
@ -47,6 +48,7 @@
|
||||
renderEffects.I renderEffects.h \
|
||||
renderModeAttrib.I renderModeAttrib.h \
|
||||
renderState.I renderState.h \
|
||||
qpsceneGraphReducer.I qpsceneGraphReducer.h \
|
||||
selectiveChildNode.I selectiveChildNode.h \
|
||||
qpsequenceNode.I qpsequenceNode.h \
|
||||
texMatrixAttrib.I texMatrixAttrib.h \
|
||||
@ -86,6 +88,7 @@
|
||||
qpfog.cxx \
|
||||
fogAttrib.cxx \
|
||||
qpgeomNode.cxx \
|
||||
qpgeomTransformer.cxx \
|
||||
qplensNode.cxx \
|
||||
qplodNode.cxx \
|
||||
materialAttrib.cxx \
|
||||
@ -98,6 +101,7 @@
|
||||
renderEffects.cxx \
|
||||
renderModeAttrib.cxx \
|
||||
renderState.cxx \
|
||||
qpsceneGraphReducer.cxx \
|
||||
selectiveChildNode.cxx \
|
||||
qpsequenceNode.cxx \
|
||||
texMatrixAttrib.cxx \
|
||||
@ -139,6 +143,7 @@
|
||||
qpfog.I qpfog.h \
|
||||
fogAttrib.I fogAttrib.h \
|
||||
qpgeomNode.I qpgeomNode.h \
|
||||
qpgeomTransformer.I qpgeomTransformer.h \
|
||||
qplensNode.I qplensNode.h \
|
||||
qplodNode.I qplodNode.h \
|
||||
materialAttrib.I materialAttrib.h \
|
||||
@ -151,6 +156,7 @@
|
||||
renderEffects.I renderEffects.h \
|
||||
renderModeAttrib.I renderModeAttrib.h \
|
||||
renderState.I renderState.h \
|
||||
qpsceneGraphReducer.I qpsceneGraphReducer.h \
|
||||
selectiveChildNode.I selectiveChildNode.h \
|
||||
qpsequenceNode.I qpsequenceNode.h \
|
||||
texMatrixAttrib.I texMatrixAttrib.h \
|
||||
|
@ -47,15 +47,15 @@ make(const LVector3f &up_vector, bool eye_relative,
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BillboardEffect::safe_to_combine
|
||||
// Function: BillboardEffect::safe_to_transform
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns true if this kind of effect can safely be
|
||||
// combined with sibling nodes that share the exact same
|
||||
// effect, or false if this is not a good idea.
|
||||
// Description: Returns true if it is generally safe to transform
|
||||
// this particular kind of RenderEffect by calling the
|
||||
// xform() method, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool BillboardEffect::
|
||||
safe_to_combine() const {
|
||||
return true;
|
||||
safe_to_transform() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -55,7 +55,7 @@ PUBLISHED:
|
||||
INLINE const LPoint3f &get_look_at_point() const;
|
||||
|
||||
public:
|
||||
virtual bool safe_to_combine() const;
|
||||
virtual bool safe_to_transform() const;
|
||||
virtual void output(ostream &out) const;
|
||||
|
||||
CPT(TransformState) do_billboard(const TransformState *net_transform,
|
||||
|
@ -70,6 +70,10 @@ ConfigureFn(config_pgraph) {
|
||||
// helps make culling errors obvious.
|
||||
const bool qpfake_view_frustum_cull = config_pgraph.GetBool("fake-view-frustum-cull", false);
|
||||
|
||||
// Set this true to make ambiguous path warning messages generate an
|
||||
// assertion failure instead of just a warning (which can then be
|
||||
// trapped with assert-abort).
|
||||
const bool unambiguous_graph = config_pgraph.GetBool("unambiguous-graph", false);
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: init_libpgraph
|
||||
|
@ -27,6 +27,7 @@ ConfigureDecl(config_pgraph, EXPCL_PANDA, EXPTP_PANDA);
|
||||
NotifyCategoryDecl(pgraph, EXPCL_PANDA, EXPTP_PANDA);
|
||||
|
||||
extern const bool qpfake_view_frustum_cull;
|
||||
extern const bool unambiguous_graph;
|
||||
|
||||
extern EXPCL_PANDA void init_libpgraph();
|
||||
|
||||
|
@ -38,7 +38,7 @@ PUBLISHED:
|
||||
};
|
||||
|
||||
private:
|
||||
INLINE CullFaceAttrib(Mode mode = M_cull_none);
|
||||
INLINE CullFaceAttrib(Mode mode = M_cull_clockwise);
|
||||
|
||||
PUBLISHED:
|
||||
static CPT(RenderAttrib) make(Mode mode);
|
||||
|
@ -35,6 +35,18 @@ make() {
|
||||
return return_new(effect);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DecalEffect::safe_to_combine
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns true if this kind of effect can safely be
|
||||
// combined with sibling nodes that share the exact same
|
||||
// effect, or false if this is not a good idea.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool DecalEffect::
|
||||
safe_to_combine() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DecalEffect::compare_to_impl
|
||||
// Access: Protected, Virtual
|
||||
|
@ -37,6 +37,7 @@ PUBLISHED:
|
||||
static CPT(RenderEffect) make();
|
||||
|
||||
protected:
|
||||
virtual bool safe_to_combine() const;
|
||||
virtual int compare_to_impl(const RenderEffect *other) const;
|
||||
virtual RenderEffect *make_default_impl() const;
|
||||
|
||||
|
@ -52,6 +52,16 @@ get_child() const {
|
||||
return _child;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::DownConnection::set_child
|
||||
// Access: Public
|
||||
// Description: This is only called by PandaNode::replace_child().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PandaNode::DownConnection::
|
||||
set_child(PandaNode *child) {
|
||||
_child = child;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::DownConnection::get_sort
|
||||
// Access: Public
|
||||
@ -151,6 +161,16 @@ Children(const PandaNode::Children ©) :
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::Children::Copy Assignment Operator
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PandaNode::Children::
|
||||
operator = (const PandaNode::Children ©) {
|
||||
_cdata = copy._cdata;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::Children::get_num_children
|
||||
// Access: Public
|
||||
@ -172,6 +192,48 @@ get_child(int n) const {
|
||||
return _cdata->_down[n].get_child();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::ChildrenCopy::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PandaNode::ChildrenCopy::
|
||||
ChildrenCopy(const PandaNode::ChildrenCopy ©) :
|
||||
_list(copy._list)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::ChildrenCopy::Copy Assignment Operator
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PandaNode::ChildrenCopy::
|
||||
operator = (const PandaNode::ChildrenCopy ©) {
|
||||
_list = copy._list;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::ChildrenCopy::get_num_children
|
||||
// Access: Public
|
||||
// Description: Returns the number of children of the node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int PandaNode::ChildrenCopy::
|
||||
get_num_children() const {
|
||||
return _list.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::ChildrenCopy::get_child
|
||||
// Access: Public
|
||||
// Description: Returns the nth child of the node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PandaNode *PandaNode::ChildrenCopy::
|
||||
get_child(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_list.size(), NULL);
|
||||
return _list[n];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::get_num_parents
|
||||
// Access: Published
|
||||
@ -715,3 +777,19 @@ get_children() const {
|
||||
return Children(cdata);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::get_children_copy
|
||||
// Access: Public
|
||||
// Description: Returns an object that can be used to walk through
|
||||
// the list of children of the node. Unlike
|
||||
// get_children(), this function actually returns an
|
||||
// object that protects you from self-modifying loops,
|
||||
// because it makes and returns a copy of the complete
|
||||
// children list.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PandaNode::ChildrenCopy PandaNode::
|
||||
get_children_copy() const {
|
||||
CDReader cdata(_cycler);
|
||||
return ChildrenCopy(cdata);
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,79 @@
|
||||
|
||||
TypeHandle PandaNode::_type_handle;
|
||||
|
||||
//
|
||||
// We go through some considerable effort in this class to ensure that
|
||||
// NodePaths are kept consistent as we attach and detach nodes. We
|
||||
// must enforce the following rules:
|
||||
//
|
||||
// 1) Each NodePath (i.e. chain of NodePathComponents) represents a
|
||||
// complete unbroken chain from a PandaNode to the root of the graph.
|
||||
//
|
||||
// 2) Each NodePathComponent chain is unique. There are no two
|
||||
// different NodePathComponents that reference the same path to the
|
||||
// root.
|
||||
//
|
||||
// 3) If a PandaNode with no parents is attached to a new parent, all
|
||||
// NodePaths that previously indicated this node as the root of graph
|
||||
// must now be updated to include the complete chain to the new root.
|
||||
//
|
||||
// 4) If a PandaNode with other parents is attached to a new parent,
|
||||
// any previously existing NodePaths are not affected.
|
||||
//
|
||||
// 5) If a PandaNode is disconnected from its parent, and it has no
|
||||
// other parents, all NodePaths that previously passed through this
|
||||
// node to the old parent must now be updated to indicate this node is
|
||||
// now the root.
|
||||
//
|
||||
// 6) If a PandaNode is disconnected from its parent, and it has at
|
||||
// least one other parent, all NodePaths that previously passed
|
||||
// through this node to the old parent must now be updated to pass
|
||||
// through one of the other parents instead.
|
||||
//
|
||||
// Rules (5) and (6) can especially complicate things because they
|
||||
// introduce the possibility that two formerly distinct NodePaths are
|
||||
// now equivalent, which violates rule (2). For example, if A is the
|
||||
// top of the graph with children B and C, and D is instanced to both
|
||||
// B and C, and E is a child of D, there might be two different
|
||||
// NodePaths to D: A/B/D/E and A/C/D/E. If you then break the
|
||||
// connection between D and E, both NodePaths must now become just the
|
||||
// singleton E.
|
||||
//
|
||||
// Unfortunately, we cannot simply remove one of the extra
|
||||
// NodePathComponents, because there may be any number of NodePath
|
||||
// objects that reference them. Instead, we define the concept of
|
||||
// "collapsed" NodePathComponents, which means one NodePathComponent
|
||||
// can be "collapsed" into a different one so that any attempt to
|
||||
// reference the first actually retrieves the second, rather like a
|
||||
// symbolic link in the file system. When the NodePath traverses its
|
||||
// component chain, it will pass right over the collapsed component in
|
||||
// favor of the one it has been collapsed into.
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// There are two different interfaces here for making and breaking
|
||||
// parent-child connections: the fundamental PandaNode interface, via
|
||||
// add_child() and remove_child() (and related functions), and the
|
||||
// NodePath support interface, via attach(), detach(), and reparent().
|
||||
// They both do essentially the same thing, but with slightly
|
||||
// different inputs. Both are responsible for keeping all NodePaths
|
||||
// up-to-date according to the above rules.
|
||||
//
|
||||
// The NodePath support interface functions are strictly called from
|
||||
// within the NodePath class, and are used to implement
|
||||
// NodePath::reparent_to() and NodePath::remove_node(), etc. The
|
||||
// fundamental interface, on the other hand, is designed to be called
|
||||
// directly by the user.
|
||||
//
|
||||
// The fundamental interface has a slightly lower overhead because it
|
||||
// does not need to create a NodePathComponent chain where one does
|
||||
// not already exist; however, the NodePath support interface is more
|
||||
// useful when the NodePath already does exist, because it ensures
|
||||
// that the particular NodePath calling it is kept appropriately
|
||||
// up-to-date.
|
||||
//
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::CData::make_copy
|
||||
@ -260,6 +333,20 @@ fillin_down_list(PandaNode::Down &down_list,
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::ChildrenCopy::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode::ChildrenCopy::
|
||||
ChildrenCopy(const PandaNode::CDReader &cdata) {
|
||||
Children cr(cdata);
|
||||
int num_children = cr.get_num_children();
|
||||
for (int i = 0; i < num_children; i++) {
|
||||
_list.push_back(cr.get_child(i));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::Constructor
|
||||
// Access: Published
|
||||
@ -396,6 +483,18 @@ safe_to_combine() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::preserve_name
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns true if the node's name has extrinsic meaning
|
||||
// and must be preserved across a flatten operation,
|
||||
// false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PandaNode::
|
||||
preserve_name() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::xform
|
||||
// Access: Public, Virtual
|
||||
@ -577,20 +676,8 @@ add_child(PandaNode *child_node, int sort) {
|
||||
|
||||
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.
|
||||
Paths::iterator pi;
|
||||
for (pi = cdata_child->_paths.begin();
|
||||
pi != cdata_child->_paths.end();
|
||||
++pi) {
|
||||
if ((*pi)->is_top_node()) {
|
||||
(*pi)->set_next(get_generic_component());
|
||||
}
|
||||
}
|
||||
child_node->fix_path_lengths(cdata_child);
|
||||
|
||||
new_connection(this, child_node);
|
||||
|
||||
// Mark the bounding volumes stale.
|
||||
force_bound_stale();
|
||||
@ -616,35 +703,8 @@ remove_child(int n) {
|
||||
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;
|
||||
Paths::iterator pi;
|
||||
pi = cdata_child->_paths.begin();
|
||||
while (pi != cdata_child->_paths.end()) {
|
||||
Paths::iterator pnext = pi;
|
||||
++pnext;
|
||||
if (!(*pi)->is_top_node() && (*pi)->get_next()->get_node() == this) {
|
||||
if (collapsed == (qpNodePathComponent *)NULL) {
|
||||
(*pi)->set_top_node();
|
||||
collapsed = (*pi);
|
||||
} 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.
|
||||
(*pi)->collapse_with(collapsed);
|
||||
cdata_child->_paths.erase(pi);
|
||||
}
|
||||
}
|
||||
pi = pnext;
|
||||
}
|
||||
|
||||
child_node->fix_path_lengths(cdata_child);
|
||||
|
||||
sever_connection(this, child_node);
|
||||
|
||||
// Mark the bounding volumes stale.
|
||||
force_bound_stale();
|
||||
@ -659,68 +719,115 @@ remove_child(int n) {
|
||||
// Access: Published
|
||||
// Description: Removes the indicated child from the node. Returns
|
||||
// true if the child was removed, false if it was not
|
||||
// already a child of the node.
|
||||
// already a child of the node. This will also
|
||||
// successfully remove the child if it had been stashed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
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(_cycler);
|
||||
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.
|
||||
// First, look for the parent in the child's up list, to ensure the
|
||||
// child is known.
|
||||
int parent_index = child_node->find_parent(this);
|
||||
if (parent_index < 0) {
|
||||
// Nope, no relation.
|
||||
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;
|
||||
Paths::iterator pi;
|
||||
pi = cdata_child->_paths.begin();
|
||||
while (pi != cdata_child->_paths.end()) {
|
||||
Paths::iterator pnext = pi;
|
||||
++pnext;
|
||||
if (!(*pi)->is_top_node() && (*pi)->get_next()->get_node() == this) {
|
||||
if (collapsed == (qpNodePathComponent *)NULL) {
|
||||
(*pi)->set_top_node();
|
||||
collapsed = (*pi);
|
||||
} else {
|
||||
(*pi)->collapse_with(collapsed);
|
||||
cdata_child->_paths.erase(pi);
|
||||
}
|
||||
}
|
||||
pi = pnext;
|
||||
|
||||
int child_index = find_child(child_node);
|
||||
if (child_index >= 0) {
|
||||
// The child exists; remove it.
|
||||
remove_child(child_index);
|
||||
return true;
|
||||
}
|
||||
|
||||
int stashed_index = find_stashed(child_node);
|
||||
if (stashed_index >= 0) {
|
||||
// The child has been stashed; remove it.
|
||||
remove_stashed(stashed_index);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Never heard of this child. This shouldn't be possible, because
|
||||
// the parent was in the child's up list, above. Must be some
|
||||
// internal error.
|
||||
nassertr(false, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::replace_child
|
||||
// Access: Published
|
||||
// Description: Searches for the orig_child node in the node's list
|
||||
// of children, and replaces it with the new_child
|
||||
// instead. Returns true if the replacement is made, or
|
||||
// false if the node is not a child.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PandaNode::
|
||||
replace_child(PandaNode *orig_child, PandaNode *new_child) {
|
||||
// First, look for the parent in the child's up list, to ensure the
|
||||
// child is known.
|
||||
int parent_index = orig_child->find_parent(this);
|
||||
if (parent_index < 0) {
|
||||
// Nope, no relation.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (orig_child == new_child) {
|
||||
// Trivial no-op.
|
||||
return true;
|
||||
}
|
||||
|
||||
child_node->fix_path_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;
|
||||
// Don't let orig_child be destructed yet.
|
||||
PT(PandaNode) keep_orig_child = orig_child;
|
||||
|
||||
int child_index = find_child(orig_child);
|
||||
if (child_index >= 0) {
|
||||
// The child exists; replace it.
|
||||
CDWriter cdata(_cycler);
|
||||
DownConnection &down = cdata->_down[child_index];
|
||||
nassertr(down.get_child() == orig_child, false);
|
||||
down.set_child(new_child);
|
||||
|
||||
} else {
|
||||
int stashed_index = find_stashed(orig_child);
|
||||
if (stashed_index >= 0) {
|
||||
// The child has been stashed; remove it.
|
||||
CDWriter cdata(_cycler);
|
||||
DownConnection &down = cdata->_stashed[stashed_index];
|
||||
nassertr(down.get_child() == orig_child, false);
|
||||
down.set_child(new_child);
|
||||
|
||||
} else {
|
||||
// Never heard of this child. This shouldn't be possible, because
|
||||
// the parent was in the child's up list, above. Must be some
|
||||
// internal error.
|
||||
nassertr(false, false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Now adjust the bookkeeping on both children.
|
||||
|
||||
CDWriter cdata_orig_child(orig_child->_cycler);
|
||||
CDWriter cdata_new_child(new_child->_cycler);
|
||||
|
||||
nassertr(found, false);
|
||||
cdata_new_child->_up.insert(UpConnection(this));
|
||||
int num_erased = cdata_orig_child->_up.erase(UpConnection(this));
|
||||
nassertr(num_erased == 1, false);
|
||||
|
||||
sever_connection(this, orig_child);
|
||||
orig_child->parents_changed();
|
||||
|
||||
new_connection(this, new_child);
|
||||
new_child->parents_changed();
|
||||
|
||||
// Mark the bounding volumes stale.
|
||||
force_bound_stale();
|
||||
|
||||
// Call callback hooks.
|
||||
children_changed();
|
||||
child_node->parents_changed();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::stash_child
|
||||
// Access: Published
|
||||
@ -745,20 +852,8 @@ stash_child(int child_index) {
|
||||
|
||||
cdata->_stashed.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.
|
||||
Paths::iterator pi;
|
||||
for (pi = cdata_child->_paths.begin();
|
||||
pi != cdata_child->_paths.end();
|
||||
++pi) {
|
||||
if ((*pi)->is_top_node()) {
|
||||
(*pi)->set_next(get_generic_component());
|
||||
}
|
||||
}
|
||||
child_node->fix_path_lengths(cdata_child);
|
||||
|
||||
new_connection(this, child_node);
|
||||
|
||||
// Mark the bounding volumes stale.
|
||||
force_bound_stale();
|
||||
@ -792,20 +887,8 @@ unstash_child(int stashed_index) {
|
||||
|
||||
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.
|
||||
Paths::iterator pi;
|
||||
for (pi = cdata_child->_paths.begin();
|
||||
pi != cdata_child->_paths.end();
|
||||
++pi) {
|
||||
if ((*pi)->is_top_node()) {
|
||||
(*pi)->set_next(get_generic_component());
|
||||
}
|
||||
}
|
||||
child_node->fix_path_lengths(cdata_child);
|
||||
|
||||
new_connection(this, child_node);
|
||||
|
||||
// Mark the bounding volumes stale.
|
||||
force_bound_stale();
|
||||
@ -837,12 +920,40 @@ find_stashed(PandaNode *node) const {
|
||||
return -1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::add_stashed
|
||||
// Access: Published
|
||||
// Description: Adds a new child to the node, directly as a stashed
|
||||
// child. The child is not added in the normal sense,
|
||||
// but will be revealed if unstash_child() is called on
|
||||
// it later.
|
||||
//
|
||||
// If the same child is added to a node more than once,
|
||||
// the previous instance is first removed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PandaNode::
|
||||
add_stashed(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->_stashed.insert(DownConnection(child_node, sort));
|
||||
cdata_child->_up.insert(UpConnection(this));
|
||||
|
||||
new_connection(this, child_node);
|
||||
|
||||
// Call callback hooks.
|
||||
children_changed();
|
||||
child_node->parents_changed();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::remove_stashed
|
||||
// Access: Published
|
||||
// Description: Removes the nth stashed child from the node. This is
|
||||
// the only way to remove a child from the node that has
|
||||
// previously been stashed, without unstashing it first.
|
||||
// Description: Removes the nth stashed child from the node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PandaNode::
|
||||
remove_stashed(int n) {
|
||||
@ -855,35 +966,8 @@ remove_stashed(int n) {
|
||||
cdata->_stashed.erase(cdata->_stashed.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;
|
||||
Paths::iterator pi;
|
||||
pi = cdata_child->_paths.begin();
|
||||
while (pi != cdata_child->_paths.end()) {
|
||||
Paths::iterator pnext = pi;
|
||||
++pnext;
|
||||
if (!(*pi)->is_top_node() && (*pi)->get_next()->get_node() == this) {
|
||||
if (collapsed == (qpNodePathComponent *)NULL) {
|
||||
(*pi)->set_top_node();
|
||||
collapsed = (*pi);
|
||||
} 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.
|
||||
(*pi)->collapse_with(collapsed);
|
||||
cdata_child->_paths.erase(pi);
|
||||
}
|
||||
}
|
||||
pi = pnext;
|
||||
}
|
||||
|
||||
child_node->fix_path_lengths(cdata_child);
|
||||
|
||||
sever_connection(this, child_node);
|
||||
|
||||
// Mark the bounding volumes stale.
|
||||
force_bound_stale();
|
||||
@ -907,29 +991,8 @@ remove_all_children() {
|
||||
PT(PandaNode) child_node = (*di).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;
|
||||
Paths::iterator pi;
|
||||
pi = cdata_child->_paths.begin();
|
||||
while (pi != cdata_child->_paths.end()) {
|
||||
Paths::iterator pnext = pi;
|
||||
++pnext;
|
||||
if (!(*pi)->is_top_node() && (*pi)->get_next()->get_node() == this) {
|
||||
if (collapsed == (qpNodePathComponent *)NULL) {
|
||||
(*pi)->set_top_node();
|
||||
collapsed = (*pi);
|
||||
} else {
|
||||
(*pi)->collapse_with(collapsed);
|
||||
cdata_child->_paths.erase(pi);
|
||||
}
|
||||
}
|
||||
pi = pnext;
|
||||
}
|
||||
|
||||
child_node->fix_path_lengths(cdata_child);
|
||||
|
||||
sever_connection(this, child_node);
|
||||
child_node->parents_changed();
|
||||
}
|
||||
cdata->_down.clear();
|
||||
@ -938,29 +1001,8 @@ remove_all_children() {
|
||||
PT(PandaNode) child_node = (*di).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;
|
||||
Paths::iterator pi;
|
||||
pi = cdata_child->_paths.begin();
|
||||
while (pi != cdata_child->_paths.end()) {
|
||||
Paths::iterator pnext = pi;
|
||||
++pnext;
|
||||
if (!(*pi)->is_top_node() && (*pi)->get_next()->get_node() == this) {
|
||||
if (collapsed == (qpNodePathComponent *)NULL) {
|
||||
(*pi)->set_top_node();
|
||||
collapsed = (*pi);
|
||||
} else {
|
||||
(*pi)->collapse_with(collapsed);
|
||||
cdata_child->_paths.erase(pi);
|
||||
}
|
||||
}
|
||||
pi = pnext;
|
||||
}
|
||||
|
||||
child_node->fix_path_lengths(cdata_child);
|
||||
|
||||
sever_connection(this, child_node);
|
||||
child_node->parents_changed();
|
||||
}
|
||||
cdata->_stashed.clear();
|
||||
@ -970,6 +1012,69 @@ remove_all_children() {
|
||||
children_changed();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::steal_children
|
||||
// Access: Published
|
||||
// Description: Moves all the children from the other node onto this
|
||||
// node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PandaNode::
|
||||
steal_children(PandaNode *other) {
|
||||
if (other == this) {
|
||||
// Trivial.
|
||||
return;
|
||||
}
|
||||
|
||||
// We do this through the high-level interface for convenience.
|
||||
// This could begin to be a problem if we have a node with hundreds
|
||||
// of children to copy; this could break down the ov_set.insert()
|
||||
// method, which is an O(n^2) operation. If this happens, we should
|
||||
// rewrite this to do a simpler add_child() operation that involves
|
||||
// push_back() instead of insert(), and then sort the down list at
|
||||
// the end.
|
||||
|
||||
int num_children = other->get_num_children();
|
||||
for (int i = 0; i < num_children; i++) {
|
||||
PandaNode *child_node = other->get_child(i);
|
||||
int sort = other->get_child_sort(i);
|
||||
add_child(child_node, sort);
|
||||
}
|
||||
int num_stashed = other->get_num_stashed();
|
||||
for (int i = 0; i < num_stashed; i++) {
|
||||
PandaNode *child_node = other->get_stashed(i);
|
||||
int sort = other->get_stashed_sort(i);
|
||||
add_stashed(child_node, sort);
|
||||
}
|
||||
|
||||
other->remove_all_children();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::copy_children
|
||||
// Access: Published
|
||||
// Description: Makes another instance of all the children of the
|
||||
// other node, copying them to this node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PandaNode::
|
||||
copy_children(PandaNode *other) {
|
||||
if (other == this) {
|
||||
// Trivial.
|
||||
return;
|
||||
}
|
||||
int num_children = other->get_num_children();
|
||||
for (int i = 0; i < num_children; i++) {
|
||||
PandaNode *child_node = other->get_child(i);
|
||||
int sort = other->get_child_sort(i);
|
||||
add_child(child_node, sort);
|
||||
}
|
||||
int num_stashed = other->get_num_stashed();
|
||||
for (int i = 0; i < num_stashed; i++) {
|
||||
PandaNode *child_node = other->get_stashed(i);
|
||||
int sort = other->get_stashed_sort(i);
|
||||
add_stashed(child_node, sort);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::output
|
||||
// Access: Published, Virtual
|
||||
@ -1191,6 +1296,7 @@ r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map) {
|
||||
CDReader from_cdata(from->_cycler);
|
||||
Down::const_iterator di;
|
||||
for (di = from_cdata->_down.begin(); di != from_cdata->_down.end(); ++di) {
|
||||
int sort = (*di).get_sort();
|
||||
PandaNode *source_child = (*di).get_child();
|
||||
PT(PandaNode) dest_child;
|
||||
|
||||
@ -1207,7 +1313,7 @@ r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map) {
|
||||
inst_map[source_child] = dest_child;
|
||||
}
|
||||
|
||||
add_child(dest_child);
|
||||
add_child(dest_child, sort);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1230,7 +1336,7 @@ attach(qpNodePathComponent *parent, PandaNode *child_node, int sort) {
|
||||
if (child == (qpNodePathComponent *)NULL) {
|
||||
// The child was not already attached to the parent, so get a new
|
||||
// component.
|
||||
child = get_top_component(child_node);
|
||||
child = get_top_component(child_node, true);
|
||||
}
|
||||
|
||||
reparent(parent, child, sort);
|
||||
@ -1403,9 +1509,14 @@ get_component(qpNodePathComponent *parent, PandaNode *child_node) {
|
||||
// this for a node that has parents, unless you are
|
||||
// about to create a new instance (and immediately
|
||||
// reconnect the qpNodePathComponent elsewhere).
|
||||
//
|
||||
// If force is true, this will always return something,
|
||||
// even if it needs to create a new top component;
|
||||
// otherwise, if force is false, it will return NULL if
|
||||
// there is not already a top component available.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(qpNodePathComponent) PandaNode::
|
||||
get_top_component(PandaNode *child_node) {
|
||||
get_top_component(PandaNode *child_node, bool force) {
|
||||
{
|
||||
CDReader cdata_child(child_node->_cycler);
|
||||
|
||||
@ -1422,6 +1533,12 @@ get_top_component(PandaNode *child_node) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!force) {
|
||||
// If we don't care to force the point, return NULL to indicate
|
||||
// there's not already a top component.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// We don't already have such a qpNodePathComponent; create and
|
||||
// return a new one.
|
||||
PT(qpNodePathComponent) child =
|
||||
@ -1445,17 +1562,28 @@ PT(qpNodePathComponent) PandaNode::
|
||||
get_generic_component() {
|
||||
int num_parents = get_num_parents();
|
||||
if (num_parents == 0) {
|
||||
return get_top_component(this);
|
||||
// No parents; no ambiguity. This is the root.
|
||||
return get_top_component(this, true);
|
||||
}
|
||||
|
||||
PT(qpNodePathComponent) result;
|
||||
if (num_parents == 1) {
|
||||
// Only one parent; no ambiguity.
|
||||
PT(qpNodePathComponent) parent = get_parent(0)->get_generic_component();
|
||||
result = get_component(parent, this);
|
||||
|
||||
} else {
|
||||
if (num_parents != 1) {
|
||||
pgraph_cat.warning()
|
||||
<< *this << " has " << num_parents
|
||||
<< " parents; choosing arbitrary path to root.\n";
|
||||
}
|
||||
// Oops, multiple parents; the NodePath is ambiguous.
|
||||
pgraph_cat.warning()
|
||||
<< *this << " has " << num_parents
|
||||
<< " parents; choosing arbitrary path to root.\n";
|
||||
|
||||
PT(qpNodePathComponent) parent = get_parent(0)->get_generic_component();
|
||||
return get_component(parent, this);
|
||||
result = get_component(parent, this);
|
||||
nassertr(!unambiguous_graph, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -1480,7 +1608,106 @@ delete_component(qpNodePathComponent *component) {
|
||||
_cycler.release_write_stage(i, cdata);
|
||||
}
|
||||
}
|
||||
nassertv(max_num_erased == 1);
|
||||
|
||||
// This may legitimately be zero if we are deleting a collapsed NodePath.
|
||||
// nassertv(max_num_erased == 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::sever_connection
|
||||
// Access: Private, Static
|
||||
// Description: This is called internally when a parent-child
|
||||
// connection is broken to update the NodePathComponents
|
||||
// that reflected this connection.
|
||||
//
|
||||
// It severs any NodePathComponents on the child node
|
||||
// that reference the indicated parent node. If the
|
||||
// child node has additional parents, chooses one of
|
||||
// them arbitrarily instead. Collapses together
|
||||
// instances below this node that used to differentiate
|
||||
// on some instance above the old parent.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PandaNode::
|
||||
sever_connection(PandaNode *parent_node, PandaNode *child_node) {
|
||||
CDWriter cdata_child(child_node->_cycler);
|
||||
qpNodePathComponent *collapsed = (qpNodePathComponent *)NULL;
|
||||
|
||||
Paths::iterator pi;
|
||||
pi = cdata_child->_paths.begin();
|
||||
while (pi != cdata_child->_paths.end()) {
|
||||
Paths::iterator pnext = pi;
|
||||
++pnext;
|
||||
if (!(*pi)->is_top_node() &&
|
||||
(*pi)->get_next()->get_node() == parent_node) {
|
||||
if (collapsed == (qpNodePathComponent *)NULL) {
|
||||
|
||||
// This is the first component we've found that references
|
||||
// this node. Should we sever it or reattach it?
|
||||
if (child_node->get_num_parents() == 0) {
|
||||
// If the node no longer has any parents, all of its paths will be
|
||||
// severed here. Collapse them all with the existing top
|
||||
// component if there is one.
|
||||
collapsed = get_top_component(child_node, false);
|
||||
|
||||
} else {
|
||||
// If the node still has one parent, all of its paths that
|
||||
// referenced the old parent will be combined with the remaining
|
||||
// parent. If there are multiple parents, choose one arbitrarily
|
||||
// to combine with.
|
||||
collapsed = child_node->get_generic_component();
|
||||
}
|
||||
|
||||
if (collapsed == (qpNodePathComponent *)NULL) {
|
||||
// Sever the component here; there's nothing to attach it
|
||||
// to.
|
||||
(*pi)->set_top_node();
|
||||
collapsed = (*pi);
|
||||
|
||||
} else {
|
||||
// Collapse the new component with the pre-existing
|
||||
// component.
|
||||
(*pi)->collapse_with(collapsed);
|
||||
cdata_child->_paths.erase(pi);
|
||||
}
|
||||
|
||||
} else {
|
||||
// This is the second (or later) component we've found that
|
||||
// references this node. We should collapse it with the first
|
||||
// one.
|
||||
(*pi)->collapse_with(collapsed);
|
||||
cdata_child->_paths.erase(pi);
|
||||
}
|
||||
}
|
||||
pi = pnext;
|
||||
}
|
||||
child_node->fix_path_lengths(cdata_child);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::new_connection
|
||||
// Access: Private, Static
|
||||
// Description: This is called internally when a parent-child
|
||||
// connection is establshed to update the
|
||||
// NodePathComponents that might be involved.
|
||||
//
|
||||
// It adjusts any NodePathComponents the child has 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.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PandaNode::
|
||||
new_connection(PandaNode *parent_node, PandaNode *child_node) {
|
||||
CDWriter cdata_child(child_node->_cycler);
|
||||
|
||||
Paths::iterator pi;
|
||||
for (pi = cdata_child->_paths.begin();
|
||||
pi != cdata_child->_paths.end();
|
||||
++pi) {
|
||||
if ((*pi)->is_top_node()) {
|
||||
(*pi)->set_next(parent_node->get_generic_component());
|
||||
}
|
||||
}
|
||||
child_node->fix_path_lengths(cdata_child);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "luse.h"
|
||||
#include "ordered_vector.h"
|
||||
#include "pointerTo.h"
|
||||
#include "pointerToArray.h"
|
||||
#include "notify.h"
|
||||
|
||||
class qpNodePathComponent;
|
||||
@ -67,6 +68,7 @@ public:
|
||||
virtual bool safe_to_flatten() const;
|
||||
virtual bool safe_to_transform() const;
|
||||
virtual bool safe_to_combine() const;
|
||||
virtual bool preserve_name() const;
|
||||
virtual void xform(const LMatrix4f &mat);
|
||||
virtual PandaNode *combine_with(PandaNode *other);
|
||||
|
||||
@ -89,18 +91,24 @@ PUBLISHED:
|
||||
void add_child(PandaNode *child_node, int sort = 0);
|
||||
void remove_child(int n);
|
||||
bool remove_child(PandaNode *child_node);
|
||||
bool replace_child(PandaNode *orig_child, PandaNode *new_child);
|
||||
|
||||
INLINE bool stash_child(PandaNode *child_node);
|
||||
void stash_child(int child_index);
|
||||
INLINE bool unstash_child(PandaNode *child_node);
|
||||
void unstash_child(int stashed_index);
|
||||
|
||||
INLINE int get_num_stashed() const;
|
||||
INLINE PandaNode *get_stashed(int n) const;
|
||||
INLINE int get_stashed_sort(int n) const;
|
||||
int find_stashed(PandaNode *node) const;
|
||||
|
||||
void add_stashed(PandaNode *child_node, int sort = 0);
|
||||
void remove_stashed(int n);
|
||||
|
||||
void remove_all_children();
|
||||
void steal_children(PandaNode *other);
|
||||
void copy_children(PandaNode *other);
|
||||
|
||||
INLINE void set_attrib(const RenderAttrib *attrib, int override = 0);
|
||||
INLINE const RenderAttrib *get_attrib(TypeHandle type) const;
|
||||
@ -173,6 +181,8 @@ protected:
|
||||
BoundedObject _internal_bound;
|
||||
|
||||
private:
|
||||
class CData;
|
||||
|
||||
// parent-child manipulation for qpNodePath support. Don't try to
|
||||
// call these directly.
|
||||
static PT(qpNodePathComponent) attach(qpNodePathComponent *parent,
|
||||
@ -182,10 +192,12 @@ private:
|
||||
qpNodePathComponent *child, int sort);
|
||||
static PT(qpNodePathComponent) get_component(qpNodePathComponent *parent,
|
||||
PandaNode *child);
|
||||
static PT(qpNodePathComponent) get_top_component(PandaNode *child);
|
||||
static PT(qpNodePathComponent) get_top_component(PandaNode *child,
|
||||
bool force);
|
||||
PT(qpNodePathComponent) get_generic_component();
|
||||
void delete_component(qpNodePathComponent *component);
|
||||
class CData;
|
||||
static void sever_connection(PandaNode *parent_node, PandaNode *child_node);
|
||||
static void new_connection(PandaNode *parent_node, PandaNode *child_node);
|
||||
void fix_path_lengths(const CData *cdata);
|
||||
void r_list_descendants(ostream &out, int indent_level) const;
|
||||
|
||||
@ -195,6 +207,7 @@ private:
|
||||
INLINE DownConnection(PandaNode *child, int sort);
|
||||
INLINE bool operator < (const DownConnection &other) const;
|
||||
INLINE PandaNode *get_child() const;
|
||||
INLINE void set_child(PandaNode *child);
|
||||
INLINE int get_sort() const;
|
||||
|
||||
private:
|
||||
@ -273,6 +286,7 @@ public:
|
||||
public:
|
||||
INLINE Children(const CDReader &cdata);
|
||||
INLINE Children(const Children ©);
|
||||
INLINE void operator = (const Children ©);
|
||||
|
||||
INLINE int get_num_children() const;
|
||||
INLINE PandaNode *get_child(int n) const;
|
||||
@ -283,6 +297,24 @@ public:
|
||||
|
||||
INLINE Children get_children() const;
|
||||
|
||||
// This interface *does* protect you from self-modifying loops, by
|
||||
// copying the list of children.
|
||||
class EXPCL_PANDA ChildrenCopy {
|
||||
public:
|
||||
ChildrenCopy(const CDReader &cdata);
|
||||
INLINE ChildrenCopy(const ChildrenCopy ©);
|
||||
INLINE void operator = (const ChildrenCopy ©);
|
||||
|
||||
INLINE int get_num_children() const;
|
||||
INLINE PandaNode *get_child(int n) const;
|
||||
|
||||
private:
|
||||
typedef PTA(PT(PandaNode)) List;
|
||||
List _list;
|
||||
};
|
||||
|
||||
INLINE ChildrenCopy get_children_copy() const;
|
||||
|
||||
public:
|
||||
static void register_with_read_factory();
|
||||
virtual void write_datagram(BamWriter *manager, Datagram &dg);
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "qpfog.cxx"
|
||||
#include "fogAttrib.cxx"
|
||||
#include "qpgeomNode.cxx"
|
||||
#include "qpgeomTransformer.cxx"
|
||||
#include "qplensNode.cxx"
|
||||
#include "qplodNode.cxx"
|
||||
#include "materialAttrib.cxx"
|
||||
@ -16,6 +17,7 @@
|
||||
#include "renderEffects.cxx"
|
||||
#include "renderModeAttrib.cxx"
|
||||
#include "renderState.cxx"
|
||||
#include "qpsceneGraphReducer.cxx"
|
||||
#include "selectiveChildNode.cxx"
|
||||
#include "qpsequenceNode.cxx"
|
||||
#include "test_pgraph.cxx"
|
||||
|
@ -112,6 +112,7 @@ add_geom(Geom *geom, const RenderState *state) {
|
||||
CDWriter cdata(_cycler);
|
||||
|
||||
cdata->_geoms.push_back(GeomEntry(geom, state));
|
||||
mark_bound_stale();
|
||||
return cdata->_geoms.size() - 1;
|
||||
}
|
||||
|
||||
@ -126,6 +127,7 @@ remove_geom(int n) {
|
||||
nassertv(n >= 0 && n < (int)cdata->_geoms.size());
|
||||
|
||||
cdata->_geoms.erase(cdata->_geoms.begin() + n);
|
||||
mark_bound_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -137,4 +139,5 @@ INLINE void qpGeomNode::
|
||||
remove_all_geoms() {
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_geoms.clear();
|
||||
mark_bound_stale();
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "qpgeomNode.h"
|
||||
#include "qpgeomTransformer.h"
|
||||
#include "bamReader.h"
|
||||
#include "bamWriter.h"
|
||||
#include "datagram.h"
|
||||
@ -153,6 +154,73 @@ make_copy() const {
|
||||
return new qpGeomNode(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomNode::xform
|
||||
// Access: Public, Virtual
|
||||
// Description: Transforms the contents of this node by the indicated
|
||||
// matrix, if it means anything to do so. For most
|
||||
// kinds of nodes, this does nothing.
|
||||
//
|
||||
// For a GeomNode, this does the right thing, but it is
|
||||
// better to use a GeomTransformer instead, since it
|
||||
// will share the new arrays properly between different
|
||||
// GeomNodes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomNode::
|
||||
xform(const LMatrix4f &mat) {
|
||||
qpGeomTransformer transformer;
|
||||
transformer.transform_vertices(this, mat);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomNode::combine_with
|
||||
// Access: Public, Virtual
|
||||
// Description: Collapses this node with the other node, if possible,
|
||||
// and returns a pointer to the combined node, or NULL
|
||||
// if the two nodes cannot safely be combined.
|
||||
//
|
||||
// The return value may be this, other, or a new node
|
||||
// altogether.
|
||||
//
|
||||
// This function is called from GraphReducer::flatten(),
|
||||
// and need not deal with children; its job is just to
|
||||
// decide whether to collapse the two nodes and what the
|
||||
// collapsed node should look like.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *qpGeomNode::
|
||||
combine_with(PandaNode *other) {
|
||||
if (is_exact_type(get_class_type()) &&
|
||||
other->is_exact_type(get_class_type())) {
|
||||
// Two GeomNodes can combine by moving Geoms from one to the other.
|
||||
qpGeomNode *gother = DCAST(qpGeomNode, other);
|
||||
add_geoms_from(gother);
|
||||
return this;
|
||||
}
|
||||
|
||||
return PandaNode::combine_with(other);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomNode::add_geoms_from
|
||||
// Access: Published
|
||||
// Description: Copies the Geoms (and their associated RenderStates)
|
||||
// from the indicated GeomNode into this one.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomNode::
|
||||
add_geoms_from(const qpGeomNode *other) {
|
||||
CDReader cdata_other(other->_cycler);
|
||||
CDWriter cdata(_cycler);
|
||||
|
||||
Geoms::const_iterator gi;
|
||||
for (gi = cdata_other->_geoms.begin();
|
||||
gi != cdata_other->_geoms.end();
|
||||
++gi) {
|
||||
const GeomEntry &entry = (*gi);
|
||||
cdata->_geoms.push_back(entry);
|
||||
}
|
||||
mark_bound_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomNode::write_geoms
|
||||
// Access: Published
|
||||
|
@ -44,6 +44,8 @@ protected:
|
||||
public:
|
||||
virtual ~qpGeomNode();
|
||||
virtual PandaNode *make_copy() const;
|
||||
virtual void xform(const LMatrix4f &mat);
|
||||
virtual PandaNode *combine_with(PandaNode *other);
|
||||
|
||||
PUBLISHED:
|
||||
INLINE int get_num_geoms() const;
|
||||
@ -52,6 +54,7 @@ PUBLISHED:
|
||||
INLINE void set_geom_state(int n, const RenderState *state);
|
||||
|
||||
INLINE int add_geom(Geom *geom, const RenderState *state = RenderState::make_empty());
|
||||
void add_geoms_from(const qpGeomNode *other);
|
||||
INLINE void remove_geom(int n);
|
||||
INLINE void remove_all_geoms();
|
||||
|
||||
@ -118,6 +121,7 @@ private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class PandaNode::Children;
|
||||
friend class qpGeomTransformer;
|
||||
};
|
||||
|
||||
#include "qpgeomNode.I"
|
||||
|
@ -159,6 +159,7 @@ fail() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool qpNodePath::
|
||||
is_empty() const {
|
||||
uncollapse_head();
|
||||
return (_head == (qpNodePathComponent *)NULL);
|
||||
}
|
||||
|
||||
@ -272,6 +273,7 @@ attach_new_node(const string &name, int sort) const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpNodePath::
|
||||
output(ostream &out) const {
|
||||
uncollapse_head();
|
||||
if (_head == (qpNodePathComponent *)NULL) {
|
||||
out << "(empty)";
|
||||
} else {
|
||||
@ -1113,6 +1115,9 @@ operator < (const qpNodePath &other) const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int qpNodePath::
|
||||
compare_to(const qpNodePath &other) const {
|
||||
uncollapse_head();
|
||||
other.uncollapse_head();
|
||||
|
||||
// Nowadays, the NodePathComponents at the head are pointerwise
|
||||
// equivalent if and only iff the NodePaths are equivalent. So we
|
||||
// only have to compare pointers.
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "plist.h"
|
||||
#include "boundingSphere.h"
|
||||
#include "qpgeomNode.h"
|
||||
#include "qpsceneGraphReducer.h"
|
||||
|
||||
// stack seems to overflow on Intel C++ at 7000. If we need more than
|
||||
// 7000, need to increase stack size.
|
||||
@ -2403,10 +2404,8 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point) {
|
||||
int qpNodePath::
|
||||
flatten_light() {
|
||||
nassertr(!is_empty(), 0);
|
||||
/*
|
||||
SceneGraphReducer gr(_graph_type);
|
||||
gr.apply_transitions(arc());
|
||||
*/
|
||||
qpSceneGraphReducer gr;
|
||||
gr.apply_attribs(node());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2436,17 +2435,13 @@ flatten_light() {
|
||||
// The return value is the number of arcs removed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int qpNodePath::
|
||||
flatten_medium(int max_children) {
|
||||
flatten_medium() {
|
||||
nassertr(!is_empty(), 0);
|
||||
/*
|
||||
SceneGraphReducer gr(_graph_type);
|
||||
gr.set_max_children(max_children);
|
||||
gr.apply_transitions(arc());
|
||||
qpSceneGraphReducer gr;
|
||||
gr.apply_attribs(node());
|
||||
int num_removed = gr.flatten(node(), false);
|
||||
|
||||
return num_removed;
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -2467,17 +2462,13 @@ flatten_medium(int max_children) {
|
||||
// because of less-effective culling.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int qpNodePath::
|
||||
flatten_strong(int max_children) {
|
||||
flatten_strong() {
|
||||
nassertr(!is_empty(), 0);
|
||||
/*
|
||||
SceneGraphReducer gr(_graph_type);
|
||||
gr.set_max_children(max_children);
|
||||
gr.apply_transitions(arc());
|
||||
qpSceneGraphReducer gr;
|
||||
gr.apply_attribs(node());
|
||||
int num_removed = gr.flatten(node(), true);
|
||||
|
||||
return num_removed;
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -477,8 +477,8 @@ PUBLISHED:
|
||||
bool calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point);
|
||||
|
||||
int flatten_light();
|
||||
int flatten_medium(int max_children = 1);
|
||||
int flatten_strong(int max_children = 1);
|
||||
int flatten_medium();
|
||||
int flatten_strong();
|
||||
|
||||
bool write_bam_file(const string &filename) const;
|
||||
|
||||
|
@ -72,8 +72,7 @@ RenderEffect::
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns true if it is generally safe to transform
|
||||
// this particular kind of RenderEffect by calling the
|
||||
// xform() method, false otherwise. For instance, it's
|
||||
// usually a bad idea to attempt to xform a Character.
|
||||
// xform() method, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool RenderEffect::
|
||||
safe_to_transform() const {
|
||||
@ -89,7 +88,7 @@ safe_to_transform() const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool RenderEffect::
|
||||
safe_to_combine() const {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -66,21 +66,27 @@ output(ostream &out) const {
|
||||
switch (get_mode()) {
|
||||
case M_none:
|
||||
out << "none";
|
||||
break;
|
||||
|
||||
case M_alpha:
|
||||
out << "alpha";
|
||||
break;
|
||||
|
||||
case M_alpha_sorted:
|
||||
out << "alpha sorted";
|
||||
break;
|
||||
|
||||
case M_multisample:
|
||||
out << "multisample";
|
||||
break;
|
||||
|
||||
case M_multisample_mask:
|
||||
out << "multisample mask";
|
||||
break;
|
||||
|
||||
case M_binary:
|
||||
out << "binary";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "config_pgui.h"
|
||||
|
||||
#include "pandaNode.h"
|
||||
#include "qpsceneGraphReducer.h"
|
||||
#include "throw_event.h"
|
||||
#include "string_utils.h"
|
||||
#include "qpnodePath.h"
|
||||
@ -122,11 +123,9 @@ xform(const LMatrix4f &mat) {
|
||||
// Apply the matrix to the previous transform.
|
||||
node->set_transform(node->get_transform()->compose(TransformState::make_mat(mat)));
|
||||
|
||||
/*
|
||||
// Now flatten the transform into the subgraph.
|
||||
SceneGraphReducer gr;
|
||||
gr.apply_transitions(arc);
|
||||
*/
|
||||
qpSceneGraphReducer gr;
|
||||
gr.apply_attribs(node);
|
||||
}
|
||||
|
||||
// Transform the frame style too.
|
||||
|
@ -28,9 +28,9 @@
|
||||
template<class CycleDataType>
|
||||
INLINE CycleDataReader<CycleDataType>::
|
||||
CycleDataReader(const PipelineCycler<CycleDataType> &cycler) :
|
||||
_cycler(cycler)
|
||||
_cycler(&cycler)
|
||||
{
|
||||
_pointer = _cycler.read();
|
||||
_pointer = _cycler->read();
|
||||
_write_pointer = (CycleDataType *)NULL;
|
||||
}
|
||||
|
||||
@ -47,10 +47,29 @@ CycleDataReader(const CycleDataReader<CycleDataType> ©) :
|
||||
_write_pointer(copy._write_pointer)
|
||||
{
|
||||
nassertv(_pointer != (const CycleDataType *)NULL);
|
||||
// We cannot copy-construct a CycleDataReader that has elevated
|
||||
// itself to a write pointer.
|
||||
// We cannot copy a CycleDataReader that has elevated itself to a
|
||||
// write pointer.
|
||||
nassertv(_write_pointer == (const CycleDataType *)NULL);
|
||||
_cycler.increment_read(_pointer);
|
||||
_cycler->increment_read(_pointer);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CycleDataReader::Copy Assignment (full)
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template<class CycleDataType>
|
||||
INLINE void CycleDataReader<CycleDataType>::
|
||||
operator = (const CycleDataReader<CycleDataType> ©) {
|
||||
_cycler = copy._cycler;
|
||||
_pointer = copy._pointer;
|
||||
_write_pointer = copy._write_pointer;
|
||||
|
||||
nassertv(_pointer != (const CycleDataType *)NULL);
|
||||
// We cannot copy a CycleDataReader that has elevated itself to a
|
||||
// write pointer.
|
||||
nassertv(_write_pointer == (const CycleDataType *)NULL);
|
||||
_cycler->increment_read(_pointer);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -65,9 +84,9 @@ INLINE CycleDataReader<CycleDataType>::
|
||||
// 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);
|
||||
((PipelineCycler<CycleDataType> *)_cycler)->release_write(_write_pointer);
|
||||
} else if (_pointer != (CycleDataType *)NULL) {
|
||||
_cycler.release_read(_pointer);
|
||||
_cycler->release_read(_pointer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,7 +99,7 @@ INLINE CycleDataReader<CycleDataType>::
|
||||
template<class CycleDataType>
|
||||
INLINE const CycleDataType *CycleDataReader<CycleDataType>::
|
||||
operator -> () const {
|
||||
nassertr(_pointer != (const CycleDataType *)NULL, _cycler.cheat());
|
||||
nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat());
|
||||
return _pointer;
|
||||
}
|
||||
|
||||
@ -93,7 +112,7 @@ operator -> () const {
|
||||
template<class CycleDataType>
|
||||
INLINE CycleDataReader<CycleDataType>::
|
||||
operator const CycleDataType * () const {
|
||||
nassertr(_pointer != (const CycleDataType *)NULL, _cycler.cheat());
|
||||
nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat());
|
||||
return _pointer;
|
||||
}
|
||||
|
||||
@ -113,7 +132,7 @@ take_pointer() {
|
||||
const CycleDataType *pointer = _pointer;
|
||||
_pointer = (CycleDataType *)NULL;
|
||||
_write_pointer = (CycleDataType *)NULL;
|
||||
nassertr(pointer != (const CycleDataType *)NULL, _cycler.cheat());
|
||||
nassertr(pointer != (const CycleDataType *)NULL, _cycler->cheat());
|
||||
return pointer;
|
||||
}
|
||||
|
||||
@ -162,6 +181,17 @@ CycleDataReader(const CycleDataReader<CycleDataType> ©) :
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CycleDataReader::Copy Assignment (trivial)
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template<class CycleDataType>
|
||||
INLINE void CycleDataReader<CycleDataType>::
|
||||
operator = (const CycleDataReader<CycleDataType> ©) {
|
||||
_pointer = copy._pointer;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CycleDataReader::Destructor (trivial)
|
||||
// Access: Public
|
||||
|
@ -41,6 +41,7 @@ class CycleDataReader {
|
||||
public:
|
||||
INLINE CycleDataReader(const PipelineCycler<CycleDataType> &cycler);
|
||||
INLINE CycleDataReader(const CycleDataReader<CycleDataType> ©);
|
||||
INLINE void operator = (const CycleDataReader<CycleDataType> ©);
|
||||
|
||||
INLINE ~CycleDataReader();
|
||||
|
||||
@ -53,7 +54,7 @@ public:
|
||||
private:
|
||||
#ifdef DO_PIPELINING
|
||||
// This is the data stored for a real pipelining implementation.
|
||||
const PipelineCycler<CycleDataType> &_cycler;
|
||||
const PipelineCycler<CycleDataType> *_cycler;
|
||||
const CycleDataType *_pointer;
|
||||
CycleDataType *_write_pointer;
|
||||
#else // !DO_PIPELINING
|
||||
|
@ -28,9 +28,39 @@
|
||||
template<class CycleDataType>
|
||||
INLINE CycleDataWriter<CycleDataType>::
|
||||
CycleDataWriter(PipelineCycler<CycleDataType> &cycler) :
|
||||
_cycler(cycler)
|
||||
_cycler(&cycler)
|
||||
{
|
||||
_pointer = _cycler.write();
|
||||
_pointer = _cycler->write();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CycleDataWriter::Copy Constructor (full)
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template<class CycleDataType>
|
||||
INLINE CycleDataWriter<CycleDataType>::
|
||||
CycleDataWriter(const CycleDataWriter<CycleDataType> ©) :
|
||||
_cycler(copy._cycler),
|
||||
_pointer(copy._pointer)
|
||||
{
|
||||
nassertv(_pointer != (CycleDataType *)NULL);
|
||||
_cycler->increment_write(_pointer);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CycleDataWriter::Copy Assigment (full)
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template<class CycleDataType>
|
||||
INLINE void CycleDataWriter<CycleDataType>::
|
||||
operator = (const CycleDataWriter<CycleDataType> ©) {
|
||||
_cycler = copy._cycler;
|
||||
_pointer = copy._pointer;
|
||||
|
||||
nassertv(_pointer != (CycleDataType *)NULL);
|
||||
_cycler->increment_write(_pointer);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -46,7 +76,7 @@ template<class CycleDataType>
|
||||
INLINE CycleDataWriter<CycleDataType>::
|
||||
CycleDataWriter(PipelineCycler<CycleDataType> &cycler,
|
||||
CycleDataWriter<CycleDataType> &take_from) :
|
||||
_cycler(cycler),
|
||||
_cycler(&cycler),
|
||||
_pointer(take_from._pointer)
|
||||
{
|
||||
take_from._pointer = (CycleDataType *)NULL;
|
||||
@ -64,9 +94,9 @@ template<class CycleDataType>
|
||||
INLINE CycleDataWriter<CycleDataType>::
|
||||
CycleDataWriter(PipelineCycler<CycleDataType> &cycler,
|
||||
CycleDataReader<CycleDataType> &take_from) :
|
||||
_cycler(cycler)
|
||||
_cycler(&cycler)
|
||||
{
|
||||
_pointer = _cycler.elevate_read(take_from.take_pointer());
|
||||
_pointer = _cycler->elevate_read(take_from.take_pointer());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -78,7 +108,7 @@ template<class CycleDataType>
|
||||
INLINE CycleDataWriter<CycleDataType>::
|
||||
~CycleDataWriter() {
|
||||
if (_pointer != (CycleDataType *)NULL) {
|
||||
_cycler.release_write(_pointer);
|
||||
_cycler->release_write(_pointer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,7 +121,7 @@ INLINE CycleDataWriter<CycleDataType>::
|
||||
template<class CycleDataType>
|
||||
INLINE CycleDataType *CycleDataWriter<CycleDataType>::
|
||||
operator -> () {
|
||||
nassertr(_pointer != (CycleDataType *)NULL, _cycler.cheat());
|
||||
nassertr(_pointer != (CycleDataType *)NULL, _cycler->cheat());
|
||||
return _pointer;
|
||||
}
|
||||
|
||||
@ -104,7 +134,7 @@ operator -> () {
|
||||
template<class CycleDataType>
|
||||
INLINE const CycleDataType *CycleDataWriter<CycleDataType>::
|
||||
operator -> () const {
|
||||
nassertr(_pointer != (CycleDataType *)NULL, _cycler.cheat());
|
||||
nassertr(_pointer != (CycleDataType *)NULL, _cycler->cheat());
|
||||
return _pointer;
|
||||
}
|
||||
|
||||
@ -117,7 +147,7 @@ operator -> () const {
|
||||
template<class CycleDataType>
|
||||
INLINE CycleDataWriter<CycleDataType>::
|
||||
operator CycleDataType * () {
|
||||
nassertr(_pointer != (CycleDataType *)NULL, _cycler.cheat());
|
||||
nassertr(_pointer != (CycleDataType *)NULL, _cycler->cheat());
|
||||
return _pointer;
|
||||
}
|
||||
|
||||
@ -135,6 +165,29 @@ CycleDataWriter(PipelineCycler<CycleDataType> &cycler) {
|
||||
_pointer = cycler.write();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CycleDataWriter::Copy Constructor (trivial)
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template<class CycleDataType>
|
||||
INLINE CycleDataWriter<CycleDataType>::
|
||||
CycleDataWriter(const CycleDataWriter<CycleDataType> ©) :
|
||||
_pointer(copy._pointer)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CycleDataWriter::Copy Assigment (trivial)
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template<class CycleDataType>
|
||||
INLINE void CycleDataWriter<CycleDataType>::
|
||||
operator = (const CycleDataWriter<CycleDataType> ©) {
|
||||
_pointer = copy._pointer;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CycleDataWriter::Constructor (trivial)
|
||||
// Access: Public
|
||||
|
@ -40,6 +40,9 @@ template<class CycleDataType>
|
||||
class CycleDataWriter {
|
||||
public:
|
||||
INLINE CycleDataWriter(PipelineCycler<CycleDataType> &cycler);
|
||||
INLINE CycleDataWriter(const CycleDataWriter<CycleDataType> ©);
|
||||
INLINE void operator = (const CycleDataWriter<CycleDataType> ©);
|
||||
|
||||
INLINE CycleDataWriter(PipelineCycler<CycleDataType> &cycler, CycleDataWriter<CycleDataType> &take_from);
|
||||
INLINE CycleDataWriter(PipelineCycler<CycleDataType> &cycler, CycleDataReader<CycleDataType> &take_from);
|
||||
|
||||
@ -53,7 +56,7 @@ public:
|
||||
private:
|
||||
#ifdef DO_PIPELINING
|
||||
// This is the data stored for a real pipelining implementation.
|
||||
PipelineCycler<CycleDataType> &_cycler;
|
||||
PipelineCycler<CycleDataType> *_cycler;
|
||||
CycleDataType *_pointer;
|
||||
#else // !DO_PIPELINING
|
||||
// This is all we need for the trivial, do-nothing implementation.
|
||||
|
@ -378,6 +378,9 @@ main(int argc, char *argv[]) {
|
||||
render.attach_new_node(camera);
|
||||
camera->set_scene(render);
|
||||
|
||||
// This is maybe here temporarily, and maybe not.
|
||||
render.set_two_sided(0);
|
||||
|
||||
// Set up a data graph for tracking user input.
|
||||
PT(PandaNode) data_root = new PandaNode("data_root");
|
||||
PandaNode *mouse = setup_mouse(data_root, window);
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "cullBinAttrib.h"
|
||||
#include "textureAttrib.h"
|
||||
#include "transparencyAttrib.h"
|
||||
#include "qpsceneGraphReducer.h"
|
||||
#include "indent.h"
|
||||
|
||||
#include <stdio.h>
|
||||
@ -362,11 +363,9 @@ generate() {
|
||||
// applying them to the vertices.
|
||||
|
||||
if (text_flatten) {
|
||||
/* ****
|
||||
SceneGraphReducer gr(RenderRelation::get_class_type());
|
||||
gr.apply_transitions(root_arc);
|
||||
qpSceneGraphReducer gr;
|
||||
gr.apply_attribs(root);
|
||||
gr.flatten(root, true);
|
||||
*/
|
||||
}
|
||||
|
||||
return root;
|
||||
|
Loading…
x
Reference in New Issue
Block a user