mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
pgraph flatten
This commit is contained in:
parent
a56e32de31
commit
9c3a3c9c22
@ -118,6 +118,7 @@ pgraphClassRenameDictionary = {
|
|||||||
'PGEntry' : 'SpPGEntry',
|
'PGEntry' : 'SpPGEntry',
|
||||||
'PGWaitBar' : 'SpPGWaitBar',
|
'PGWaitBar' : 'SpPGWaitBar',
|
||||||
'PartBundleNode' : 'SpPartBundleNode',
|
'PartBundleNode' : 'SpPartBundleNode',
|
||||||
|
'SceneGraphReducer' : 'SpSceneGraphReducer',
|
||||||
'SequenceNode' : 'SpSequenceNode',
|
'SequenceNode' : 'SpSequenceNode',
|
||||||
'TextNode' : 'SpTextNode',
|
'TextNode' : 'SpTextNode',
|
||||||
'Trackball' : 'SpTrackball',
|
'Trackball' : 'SpTrackball',
|
||||||
@ -150,6 +151,7 @@ pgraphClassRenameDictionary = {
|
|||||||
'QpPGEntry' : 'PGEntry',
|
'QpPGEntry' : 'PGEntry',
|
||||||
'QpPGWaitBar' : 'PGWaitBar',
|
'QpPGWaitBar' : 'PGWaitBar',
|
||||||
'QpPartBundleNode' : 'PartBundleNode',
|
'QpPartBundleNode' : 'PartBundleNode',
|
||||||
|
'QpSceneGraphReducer' : 'SceneGraphReducer',
|
||||||
'QpSequenceNode' : 'SequenceNode',
|
'QpSequenceNode' : 'SequenceNode',
|
||||||
'QpTextNode' : 'TextNode',
|
'QpTextNode' : 'TextNode',
|
||||||
'QpTrackball' : 'Trackball',
|
'QpTrackball' : 'Trackball',
|
||||||
|
@ -216,6 +216,7 @@ class ShowBase:
|
|||||||
rendering 3-d geometry.
|
rendering 3-d geometry.
|
||||||
"""
|
"""
|
||||||
self.render = NodePath('render')
|
self.render = NodePath('render')
|
||||||
|
self.render.setTwoSided(0)
|
||||||
|
|
||||||
def setupRender2d(self):
|
def setupRender2d(self):
|
||||||
"""setupRender2d(self)
|
"""setupRender2d(self)
|
||||||
|
@ -1008,7 +1008,6 @@ setup_bucket(BuilderBucket &bucket, PandaNode *parent,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
bucket.add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_none));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1050,9 +1049,6 @@ setup_bucket(BuilderBucket &bucket, PandaNode *parent,
|
|||||||
// The primitive is marked with backface culling disabled--we want
|
// The primitive is marked with backface culling disabled--we want
|
||||||
// to see both sides.
|
// to see both sides.
|
||||||
bucket.add_attrib(CullFaceAttrib::make(CullFaceAttrib::M_cull_none));
|
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 "qpload_egg_file.h"
|
||||||
#include "qpeggLoader.h"
|
#include "qpeggLoader.h"
|
||||||
#include "config_egg2pg.h"
|
#include "config_egg2pg.h"
|
||||||
|
#include "qpsceneGraphReducer.h"
|
||||||
/*
|
|
||||||
#include "sceneGraphReducer.h"
|
|
||||||
#include "renderRelation.h"
|
#include "renderRelation.h"
|
||||||
*/
|
|
||||||
|
|
||||||
static PT(PandaNode)
|
static PT(PandaNode)
|
||||||
load_from_loader(qpEggLoader &loader) {
|
load_from_loader(qpEggLoader &loader) {
|
||||||
@ -37,13 +34,11 @@ load_from_loader(qpEggLoader &loader) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (loader._root != (PandaNode *)NULL && egg_flatten) {
|
||||||
if (loader._root != (NamedNode *)NULL && egg_flatten) {
|
qpSceneGraphReducer gr;
|
||||||
SceneGraphReducer gr(RenderRelation::get_class_type());
|
|
||||||
int num_reduced = gr.flatten(loader._root, egg_flatten_siblings);
|
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;
|
return loader._root;
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
qpfog.I qpfog.h \
|
qpfog.I qpfog.h \
|
||||||
fogAttrib.I fogAttrib.h \
|
fogAttrib.I fogAttrib.h \
|
||||||
qpgeomNode.I qpgeomNode.h \
|
qpgeomNode.I qpgeomNode.h \
|
||||||
|
qpgeomTransformer.I qpgeomTransformer.h \
|
||||||
qplensNode.I qplensNode.h \
|
qplensNode.I qplensNode.h \
|
||||||
qplodNode.I qplodNode.h \
|
qplodNode.I qplodNode.h \
|
||||||
materialAttrib.I materialAttrib.h \
|
materialAttrib.I materialAttrib.h \
|
||||||
@ -47,6 +48,7 @@
|
|||||||
renderEffects.I renderEffects.h \
|
renderEffects.I renderEffects.h \
|
||||||
renderModeAttrib.I renderModeAttrib.h \
|
renderModeAttrib.I renderModeAttrib.h \
|
||||||
renderState.I renderState.h \
|
renderState.I renderState.h \
|
||||||
|
qpsceneGraphReducer.I qpsceneGraphReducer.h \
|
||||||
selectiveChildNode.I selectiveChildNode.h \
|
selectiveChildNode.I selectiveChildNode.h \
|
||||||
qpsequenceNode.I qpsequenceNode.h \
|
qpsequenceNode.I qpsequenceNode.h \
|
||||||
texMatrixAttrib.I texMatrixAttrib.h \
|
texMatrixAttrib.I texMatrixAttrib.h \
|
||||||
@ -86,6 +88,7 @@
|
|||||||
qpfog.cxx \
|
qpfog.cxx \
|
||||||
fogAttrib.cxx \
|
fogAttrib.cxx \
|
||||||
qpgeomNode.cxx \
|
qpgeomNode.cxx \
|
||||||
|
qpgeomTransformer.cxx \
|
||||||
qplensNode.cxx \
|
qplensNode.cxx \
|
||||||
qplodNode.cxx \
|
qplodNode.cxx \
|
||||||
materialAttrib.cxx \
|
materialAttrib.cxx \
|
||||||
@ -98,6 +101,7 @@
|
|||||||
renderEffects.cxx \
|
renderEffects.cxx \
|
||||||
renderModeAttrib.cxx \
|
renderModeAttrib.cxx \
|
||||||
renderState.cxx \
|
renderState.cxx \
|
||||||
|
qpsceneGraphReducer.cxx \
|
||||||
selectiveChildNode.cxx \
|
selectiveChildNode.cxx \
|
||||||
qpsequenceNode.cxx \
|
qpsequenceNode.cxx \
|
||||||
texMatrixAttrib.cxx \
|
texMatrixAttrib.cxx \
|
||||||
@ -139,6 +143,7 @@
|
|||||||
qpfog.I qpfog.h \
|
qpfog.I qpfog.h \
|
||||||
fogAttrib.I fogAttrib.h \
|
fogAttrib.I fogAttrib.h \
|
||||||
qpgeomNode.I qpgeomNode.h \
|
qpgeomNode.I qpgeomNode.h \
|
||||||
|
qpgeomTransformer.I qpgeomTransformer.h \
|
||||||
qplensNode.I qplensNode.h \
|
qplensNode.I qplensNode.h \
|
||||||
qplodNode.I qplodNode.h \
|
qplodNode.I qplodNode.h \
|
||||||
materialAttrib.I materialAttrib.h \
|
materialAttrib.I materialAttrib.h \
|
||||||
@ -151,6 +156,7 @@
|
|||||||
renderEffects.I renderEffects.h \
|
renderEffects.I renderEffects.h \
|
||||||
renderModeAttrib.I renderModeAttrib.h \
|
renderModeAttrib.I renderModeAttrib.h \
|
||||||
renderState.I renderState.h \
|
renderState.I renderState.h \
|
||||||
|
qpsceneGraphReducer.I qpsceneGraphReducer.h \
|
||||||
selectiveChildNode.I selectiveChildNode.h \
|
selectiveChildNode.I selectiveChildNode.h \
|
||||||
qpsequenceNode.I qpsequenceNode.h \
|
qpsequenceNode.I qpsequenceNode.h \
|
||||||
texMatrixAttrib.I texMatrixAttrib.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
|
// Access: Public, Virtual
|
||||||
// Description: Returns true if this kind of effect can safely be
|
// Description: Returns true if it is generally safe to transform
|
||||||
// combined with sibling nodes that share the exact same
|
// this particular kind of RenderEffect by calling the
|
||||||
// effect, or false if this is not a good idea.
|
// xform() method, false otherwise.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool BillboardEffect::
|
bool BillboardEffect::
|
||||||
safe_to_combine() const {
|
safe_to_transform() const {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
@ -55,7 +55,7 @@ PUBLISHED:
|
|||||||
INLINE const LPoint3f &get_look_at_point() const;
|
INLINE const LPoint3f &get_look_at_point() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual bool safe_to_combine() const;
|
virtual bool safe_to_transform() const;
|
||||||
virtual void output(ostream &out) const;
|
virtual void output(ostream &out) const;
|
||||||
|
|
||||||
CPT(TransformState) do_billboard(const TransformState *net_transform,
|
CPT(TransformState) do_billboard(const TransformState *net_transform,
|
||||||
|
@ -70,6 +70,10 @@ ConfigureFn(config_pgraph) {
|
|||||||
// helps make culling errors obvious.
|
// helps make culling errors obvious.
|
||||||
const bool qpfake_view_frustum_cull = config_pgraph.GetBool("fake-view-frustum-cull", false);
|
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
|
// Function: init_libpgraph
|
||||||
|
@ -27,6 +27,7 @@ ConfigureDecl(config_pgraph, EXPCL_PANDA, EXPTP_PANDA);
|
|||||||
NotifyCategoryDecl(pgraph, EXPCL_PANDA, EXPTP_PANDA);
|
NotifyCategoryDecl(pgraph, EXPCL_PANDA, EXPTP_PANDA);
|
||||||
|
|
||||||
extern const bool qpfake_view_frustum_cull;
|
extern const bool qpfake_view_frustum_cull;
|
||||||
|
extern const bool unambiguous_graph;
|
||||||
|
|
||||||
extern EXPCL_PANDA void init_libpgraph();
|
extern EXPCL_PANDA void init_libpgraph();
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ PUBLISHED:
|
|||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
INLINE CullFaceAttrib(Mode mode = M_cull_none);
|
INLINE CullFaceAttrib(Mode mode = M_cull_clockwise);
|
||||||
|
|
||||||
PUBLISHED:
|
PUBLISHED:
|
||||||
static CPT(RenderAttrib) make(Mode mode);
|
static CPT(RenderAttrib) make(Mode mode);
|
||||||
|
@ -35,6 +35,18 @@ make() {
|
|||||||
return return_new(effect);
|
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
|
// Function: DecalEffect::compare_to_impl
|
||||||
// Access: Protected, Virtual
|
// Access: Protected, Virtual
|
||||||
|
@ -37,6 +37,7 @@ PUBLISHED:
|
|||||||
static CPT(RenderEffect) make();
|
static CPT(RenderEffect) make();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual bool safe_to_combine() const;
|
||||||
virtual int compare_to_impl(const RenderEffect *other) const;
|
virtual int compare_to_impl(const RenderEffect *other) const;
|
||||||
virtual RenderEffect *make_default_impl() const;
|
virtual RenderEffect *make_default_impl() const;
|
||||||
|
|
||||||
|
@ -52,6 +52,16 @@ get_child() const {
|
|||||||
return _child;
|
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
|
// Function: PandaNode::DownConnection::get_sort
|
||||||
// Access: Public
|
// 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
|
// Function: PandaNode::Children::get_num_children
|
||||||
// Access: Public
|
// Access: Public
|
||||||
@ -172,6 +192,48 @@ get_child(int n) const {
|
|||||||
return _cdata->_down[n].get_child();
|
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
|
// Function: PandaNode::get_num_parents
|
||||||
// Access: Published
|
// Access: Published
|
||||||
@ -715,3 +777,19 @@ get_children() const {
|
|||||||
return Children(cdata);
|
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;
|
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
|
// 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
|
// Function: PandaNode::Constructor
|
||||||
// Access: Published
|
// Access: Published
|
||||||
@ -396,6 +483,18 @@ safe_to_combine() const {
|
|||||||
return true;
|
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
|
// Function: PandaNode::xform
|
||||||
// Access: Public, Virtual
|
// Access: Public, Virtual
|
||||||
@ -578,19 +677,7 @@ add_child(PandaNode *child_node, int sort) {
|
|||||||
cdata->_down.insert(DownConnection(child_node, sort));
|
cdata->_down.insert(DownConnection(child_node, sort));
|
||||||
cdata_child->_up.insert(UpConnection(this));
|
cdata_child->_up.insert(UpConnection(this));
|
||||||
|
|
||||||
// We also have to adjust any qpNodePathComponents the child might
|
new_connection(this, child_node);
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Mark the bounding volumes stale.
|
// Mark the bounding volumes stale.
|
||||||
force_bound_stale();
|
force_bound_stale();
|
||||||
@ -617,34 +704,7 @@ remove_child(int n) {
|
|||||||
int num_erased = cdata_child->_up.erase(UpConnection(this));
|
int num_erased = cdata_child->_up.erase(UpConnection(this));
|
||||||
nassertv(num_erased == 1);
|
nassertv(num_erased == 1);
|
||||||
|
|
||||||
// Now sever any qpNodePathComponents on the child that reference
|
sever_connection(this, child_node);
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Mark the bounding volumes stale.
|
// Mark the bounding volumes stale.
|
||||||
force_bound_stale();
|
force_bound_stale();
|
||||||
@ -659,68 +719,115 @@ remove_child(int n) {
|
|||||||
// Access: Published
|
// Access: Published
|
||||||
// Description: Removes the indicated child from the node. Returns
|
// Description: Removes the indicated child from the node. Returns
|
||||||
// true if the child was removed, false if it was not
|
// 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::
|
bool PandaNode::
|
||||||
remove_child(PandaNode *child_node) {
|
remove_child(PandaNode *child_node) {
|
||||||
// Ensure the child_node is not deleted while we do this.
|
// First, look for the parent in the child's up list, to ensure the
|
||||||
PT(PandaNode) keep_child = child_node;
|
// child is known.
|
||||||
|
int parent_index = child_node->find_parent(this);
|
||||||
CDWriter cdata(_cycler);
|
if (parent_index < 0) {
|
||||||
CDWriter cdata_child(child_node->_cycler);
|
// Nope, no relation.
|
||||||
|
|
||||||
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now sever any qpNodePathComponents on the child that reference
|
int child_index = find_child(child_node);
|
||||||
// this node. If we have multiple of these, we have to collapse
|
if (child_index >= 0) {
|
||||||
// them together (see above).
|
// The child exists; remove it.
|
||||||
qpNodePathComponent *collapsed = (qpNodePathComponent *)NULL;
|
remove_child(child_index);
|
||||||
Paths::iterator pi;
|
return true;
|
||||||
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);
|
int stashed_index = find_stashed(child_node);
|
||||||
|
if (stashed_index >= 0) {
|
||||||
|
// The child has been stashed; remove it.
|
||||||
|
remove_stashed(stashed_index);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Now, look for and remove the child node from our down list.
|
// Never heard of this child. This shouldn't be possible, because
|
||||||
Down::iterator di;
|
// the parent was in the child's up list, above. Must be some
|
||||||
bool found = false;
|
// internal error.
|
||||||
for (di = cdata->_down.begin(); di != cdata->_down.end() && !found; ++di) {
|
nassertr(false, false);
|
||||||
if ((*di).get_child() == child_node) {
|
return false;
|
||||||
cdata->_down.erase(di);
|
}
|
||||||
found = true;
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nassertr(found, false);
|
// Now adjust the bookkeeping on both children.
|
||||||
|
|
||||||
|
CDWriter cdata_orig_child(orig_child->_cycler);
|
||||||
|
CDWriter cdata_new_child(new_child->_cycler);
|
||||||
|
|
||||||
|
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.
|
// Mark the bounding volumes stale.
|
||||||
force_bound_stale();
|
force_bound_stale();
|
||||||
|
|
||||||
// Call callback hooks.
|
|
||||||
children_changed();
|
children_changed();
|
||||||
child_node->parents_changed();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: PandaNode::stash_child
|
// Function: PandaNode::stash_child
|
||||||
// Access: Published
|
// Access: Published
|
||||||
@ -746,19 +853,7 @@ stash_child(int child_index) {
|
|||||||
cdata->_stashed.insert(DownConnection(child_node, sort));
|
cdata->_stashed.insert(DownConnection(child_node, sort));
|
||||||
cdata_child->_up.insert(UpConnection(this));
|
cdata_child->_up.insert(UpConnection(this));
|
||||||
|
|
||||||
// We also have to adjust any qpNodePathComponents the child might
|
new_connection(this, child_node);
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Mark the bounding volumes stale.
|
// Mark the bounding volumes stale.
|
||||||
force_bound_stale();
|
force_bound_stale();
|
||||||
@ -793,19 +888,7 @@ unstash_child(int stashed_index) {
|
|||||||
cdata->_down.insert(DownConnection(child_node, sort));
|
cdata->_down.insert(DownConnection(child_node, sort));
|
||||||
cdata_child->_up.insert(UpConnection(this));
|
cdata_child->_up.insert(UpConnection(this));
|
||||||
|
|
||||||
// We also have to adjust any qpNodePathComponents the child might
|
new_connection(this, child_node);
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Mark the bounding volumes stale.
|
// Mark the bounding volumes stale.
|
||||||
force_bound_stale();
|
force_bound_stale();
|
||||||
@ -837,12 +920,40 @@ find_stashed(PandaNode *node) const {
|
|||||||
return -1;
|
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
|
// Function: PandaNode::remove_stashed
|
||||||
// Access: Published
|
// Access: Published
|
||||||
// Description: Removes the nth stashed child from the node. This is
|
// Description: Removes the nth stashed child from the node.
|
||||||
// the only way to remove a child from the node that has
|
|
||||||
// previously been stashed, without unstashing it first.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void PandaNode::
|
void PandaNode::
|
||||||
remove_stashed(int n) {
|
remove_stashed(int n) {
|
||||||
@ -856,34 +967,7 @@ remove_stashed(int n) {
|
|||||||
int num_erased = cdata_child->_up.erase(UpConnection(this));
|
int num_erased = cdata_child->_up.erase(UpConnection(this));
|
||||||
nassertv(num_erased == 1);
|
nassertv(num_erased == 1);
|
||||||
|
|
||||||
// Now sever any qpNodePathComponents on the child that reference
|
sever_connection(this, child_node);
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Mark the bounding volumes stale.
|
// Mark the bounding volumes stale.
|
||||||
force_bound_stale();
|
force_bound_stale();
|
||||||
@ -908,28 +992,7 @@ remove_all_children() {
|
|||||||
CDWriter cdata_child(child_node->_cycler);
|
CDWriter cdata_child(child_node->_cycler);
|
||||||
cdata_child->_up.erase(UpConnection(this));
|
cdata_child->_up.erase(UpConnection(this));
|
||||||
|
|
||||||
// Now sever any qpNodePathComponents on the child that
|
sever_connection(this, child_node);
|
||||||
// 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);
|
|
||||||
child_node->parents_changed();
|
child_node->parents_changed();
|
||||||
}
|
}
|
||||||
cdata->_down.clear();
|
cdata->_down.clear();
|
||||||
@ -939,28 +1002,7 @@ remove_all_children() {
|
|||||||
CDWriter cdata_child(child_node->_cycler);
|
CDWriter cdata_child(child_node->_cycler);
|
||||||
cdata_child->_up.erase(UpConnection(this));
|
cdata_child->_up.erase(UpConnection(this));
|
||||||
|
|
||||||
// Now sever any qpNodePathComponents on the child that
|
sever_connection(this, child_node);
|
||||||
// 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);
|
|
||||||
child_node->parents_changed();
|
child_node->parents_changed();
|
||||||
}
|
}
|
||||||
cdata->_stashed.clear();
|
cdata->_stashed.clear();
|
||||||
@ -970,6 +1012,69 @@ remove_all_children() {
|
|||||||
children_changed();
|
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
|
// Function: PandaNode::output
|
||||||
// Access: Published, Virtual
|
// Access: Published, Virtual
|
||||||
@ -1191,6 +1296,7 @@ r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map) {
|
|||||||
CDReader from_cdata(from->_cycler);
|
CDReader from_cdata(from->_cycler);
|
||||||
Down::const_iterator di;
|
Down::const_iterator di;
|
||||||
for (di = from_cdata->_down.begin(); di != from_cdata->_down.end(); ++di) {
|
for (di = from_cdata->_down.begin(); di != from_cdata->_down.end(); ++di) {
|
||||||
|
int sort = (*di).get_sort();
|
||||||
PandaNode *source_child = (*di).get_child();
|
PandaNode *source_child = (*di).get_child();
|
||||||
PT(PandaNode) dest_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;
|
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) {
|
if (child == (qpNodePathComponent *)NULL) {
|
||||||
// The child was not already attached to the parent, so get a new
|
// The child was not already attached to the parent, so get a new
|
||||||
// component.
|
// component.
|
||||||
child = get_top_component(child_node);
|
child = get_top_component(child_node, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
reparent(parent, child, sort);
|
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
|
// this for a node that has parents, unless you are
|
||||||
// about to create a new instance (and immediately
|
// about to create a new instance (and immediately
|
||||||
// reconnect the qpNodePathComponent elsewhere).
|
// 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::
|
PT(qpNodePathComponent) PandaNode::
|
||||||
get_top_component(PandaNode *child_node) {
|
get_top_component(PandaNode *child_node, bool force) {
|
||||||
{
|
{
|
||||||
CDReader cdata_child(child_node->_cycler);
|
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
|
// We don't already have such a qpNodePathComponent; create and
|
||||||
// return a new one.
|
// return a new one.
|
||||||
PT(qpNodePathComponent) child =
|
PT(qpNodePathComponent) child =
|
||||||
@ -1445,17 +1562,28 @@ PT(qpNodePathComponent) PandaNode::
|
|||||||
get_generic_component() {
|
get_generic_component() {
|
||||||
int num_parents = get_num_parents();
|
int num_parents = get_num_parents();
|
||||||
if (num_parents == 0) {
|
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 {
|
} else {
|
||||||
if (num_parents != 1) {
|
// Oops, multiple parents; the NodePath is ambiguous.
|
||||||
pgraph_cat.warning()
|
pgraph_cat.warning()
|
||||||
<< *this << " has " << num_parents
|
<< *this << " has " << num_parents
|
||||||
<< " parents; choosing arbitrary path to root.\n";
|
<< " parents; choosing arbitrary path to root.\n";
|
||||||
}
|
|
||||||
PT(qpNodePathComponent) parent = get_parent(0)->get_generic_component();
|
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);
|
_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 "luse.h"
|
||||||
#include "ordered_vector.h"
|
#include "ordered_vector.h"
|
||||||
#include "pointerTo.h"
|
#include "pointerTo.h"
|
||||||
|
#include "pointerToArray.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
|
|
||||||
class qpNodePathComponent;
|
class qpNodePathComponent;
|
||||||
@ -67,6 +68,7 @@ public:
|
|||||||
virtual bool safe_to_flatten() const;
|
virtual bool safe_to_flatten() const;
|
||||||
virtual bool safe_to_transform() const;
|
virtual bool safe_to_transform() const;
|
||||||
virtual bool safe_to_combine() const;
|
virtual bool safe_to_combine() const;
|
||||||
|
virtual bool preserve_name() const;
|
||||||
virtual void xform(const LMatrix4f &mat);
|
virtual void xform(const LMatrix4f &mat);
|
||||||
virtual PandaNode *combine_with(PandaNode *other);
|
virtual PandaNode *combine_with(PandaNode *other);
|
||||||
|
|
||||||
@ -89,18 +91,24 @@ PUBLISHED:
|
|||||||
void add_child(PandaNode *child_node, int sort = 0);
|
void add_child(PandaNode *child_node, int sort = 0);
|
||||||
void remove_child(int n);
|
void remove_child(int n);
|
||||||
bool remove_child(PandaNode *child_node);
|
bool remove_child(PandaNode *child_node);
|
||||||
|
bool replace_child(PandaNode *orig_child, PandaNode *new_child);
|
||||||
|
|
||||||
INLINE bool stash_child(PandaNode *child_node);
|
INLINE bool stash_child(PandaNode *child_node);
|
||||||
void stash_child(int child_index);
|
void stash_child(int child_index);
|
||||||
INLINE bool unstash_child(PandaNode *child_node);
|
INLINE bool unstash_child(PandaNode *child_node);
|
||||||
void unstash_child(int stashed_index);
|
void unstash_child(int stashed_index);
|
||||||
|
|
||||||
INLINE int get_num_stashed() const;
|
INLINE int get_num_stashed() const;
|
||||||
INLINE PandaNode *get_stashed(int n) const;
|
INLINE PandaNode *get_stashed(int n) const;
|
||||||
INLINE int get_stashed_sort(int n) const;
|
INLINE int get_stashed_sort(int n) const;
|
||||||
int find_stashed(PandaNode *node) const;
|
int find_stashed(PandaNode *node) const;
|
||||||
|
|
||||||
|
void add_stashed(PandaNode *child_node, int sort = 0);
|
||||||
void remove_stashed(int n);
|
void remove_stashed(int n);
|
||||||
|
|
||||||
void remove_all_children();
|
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 void set_attrib(const RenderAttrib *attrib, int override = 0);
|
||||||
INLINE const RenderAttrib *get_attrib(TypeHandle type) const;
|
INLINE const RenderAttrib *get_attrib(TypeHandle type) const;
|
||||||
@ -173,6 +181,8 @@ protected:
|
|||||||
BoundedObject _internal_bound;
|
BoundedObject _internal_bound;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class CData;
|
||||||
|
|
||||||
// parent-child manipulation for qpNodePath support. Don't try to
|
// parent-child manipulation for qpNodePath support. Don't try to
|
||||||
// call these directly.
|
// call these directly.
|
||||||
static PT(qpNodePathComponent) attach(qpNodePathComponent *parent,
|
static PT(qpNodePathComponent) attach(qpNodePathComponent *parent,
|
||||||
@ -182,10 +192,12 @@ private:
|
|||||||
qpNodePathComponent *child, int sort);
|
qpNodePathComponent *child, int sort);
|
||||||
static PT(qpNodePathComponent) get_component(qpNodePathComponent *parent,
|
static PT(qpNodePathComponent) get_component(qpNodePathComponent *parent,
|
||||||
PandaNode *child);
|
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();
|
PT(qpNodePathComponent) get_generic_component();
|
||||||
void delete_component(qpNodePathComponent *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 fix_path_lengths(const CData *cdata);
|
||||||
void r_list_descendants(ostream &out, int indent_level) const;
|
void r_list_descendants(ostream &out, int indent_level) const;
|
||||||
|
|
||||||
@ -195,6 +207,7 @@ private:
|
|||||||
INLINE DownConnection(PandaNode *child, int sort);
|
INLINE DownConnection(PandaNode *child, int sort);
|
||||||
INLINE bool operator < (const DownConnection &other) const;
|
INLINE bool operator < (const DownConnection &other) const;
|
||||||
INLINE PandaNode *get_child() const;
|
INLINE PandaNode *get_child() const;
|
||||||
|
INLINE void set_child(PandaNode *child);
|
||||||
INLINE int get_sort() const;
|
INLINE int get_sort() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -273,6 +286,7 @@ public:
|
|||||||
public:
|
public:
|
||||||
INLINE Children(const CDReader &cdata);
|
INLINE Children(const CDReader &cdata);
|
||||||
INLINE Children(const Children ©);
|
INLINE Children(const Children ©);
|
||||||
|
INLINE void operator = (const Children ©);
|
||||||
|
|
||||||
INLINE int get_num_children() const;
|
INLINE int get_num_children() const;
|
||||||
INLINE PandaNode *get_child(int n) const;
|
INLINE PandaNode *get_child(int n) const;
|
||||||
@ -283,6 +297,24 @@ public:
|
|||||||
|
|
||||||
INLINE Children get_children() const;
|
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:
|
public:
|
||||||
static void register_with_read_factory();
|
static void register_with_read_factory();
|
||||||
virtual void write_datagram(BamWriter *manager, Datagram &dg);
|
virtual void write_datagram(BamWriter *manager, Datagram &dg);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "qpfog.cxx"
|
#include "qpfog.cxx"
|
||||||
#include "fogAttrib.cxx"
|
#include "fogAttrib.cxx"
|
||||||
#include "qpgeomNode.cxx"
|
#include "qpgeomNode.cxx"
|
||||||
|
#include "qpgeomTransformer.cxx"
|
||||||
#include "qplensNode.cxx"
|
#include "qplensNode.cxx"
|
||||||
#include "qplodNode.cxx"
|
#include "qplodNode.cxx"
|
||||||
#include "materialAttrib.cxx"
|
#include "materialAttrib.cxx"
|
||||||
@ -16,6 +17,7 @@
|
|||||||
#include "renderEffects.cxx"
|
#include "renderEffects.cxx"
|
||||||
#include "renderModeAttrib.cxx"
|
#include "renderModeAttrib.cxx"
|
||||||
#include "renderState.cxx"
|
#include "renderState.cxx"
|
||||||
|
#include "qpsceneGraphReducer.cxx"
|
||||||
#include "selectiveChildNode.cxx"
|
#include "selectiveChildNode.cxx"
|
||||||
#include "qpsequenceNode.cxx"
|
#include "qpsequenceNode.cxx"
|
||||||
#include "test_pgraph.cxx"
|
#include "test_pgraph.cxx"
|
||||||
|
@ -112,6 +112,7 @@ add_geom(Geom *geom, const RenderState *state) {
|
|||||||
CDWriter cdata(_cycler);
|
CDWriter cdata(_cycler);
|
||||||
|
|
||||||
cdata->_geoms.push_back(GeomEntry(geom, state));
|
cdata->_geoms.push_back(GeomEntry(geom, state));
|
||||||
|
mark_bound_stale();
|
||||||
return cdata->_geoms.size() - 1;
|
return cdata->_geoms.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,6 +127,7 @@ remove_geom(int n) {
|
|||||||
nassertv(n >= 0 && n < (int)cdata->_geoms.size());
|
nassertv(n >= 0 && n < (int)cdata->_geoms.size());
|
||||||
|
|
||||||
cdata->_geoms.erase(cdata->_geoms.begin() + n);
|
cdata->_geoms.erase(cdata->_geoms.begin() + n);
|
||||||
|
mark_bound_stale();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -137,4 +139,5 @@ INLINE void qpGeomNode::
|
|||||||
remove_all_geoms() {
|
remove_all_geoms() {
|
||||||
CDWriter cdata(_cycler);
|
CDWriter cdata(_cycler);
|
||||||
cdata->_geoms.clear();
|
cdata->_geoms.clear();
|
||||||
|
mark_bound_stale();
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "qpgeomNode.h"
|
#include "qpgeomNode.h"
|
||||||
|
#include "qpgeomTransformer.h"
|
||||||
#include "bamReader.h"
|
#include "bamReader.h"
|
||||||
#include "bamWriter.h"
|
#include "bamWriter.h"
|
||||||
#include "datagram.h"
|
#include "datagram.h"
|
||||||
@ -153,6 +154,73 @@ make_copy() const {
|
|||||||
return new qpGeomNode(*this);
|
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
|
// Function: qpGeomNode::write_geoms
|
||||||
// Access: Published
|
// Access: Published
|
||||||
|
@ -44,6 +44,8 @@ protected:
|
|||||||
public:
|
public:
|
||||||
virtual ~qpGeomNode();
|
virtual ~qpGeomNode();
|
||||||
virtual PandaNode *make_copy() const;
|
virtual PandaNode *make_copy() const;
|
||||||
|
virtual void xform(const LMatrix4f &mat);
|
||||||
|
virtual PandaNode *combine_with(PandaNode *other);
|
||||||
|
|
||||||
PUBLISHED:
|
PUBLISHED:
|
||||||
INLINE int get_num_geoms() const;
|
INLINE int get_num_geoms() const;
|
||||||
@ -52,6 +54,7 @@ PUBLISHED:
|
|||||||
INLINE void set_geom_state(int n, const RenderState *state);
|
INLINE void set_geom_state(int n, const RenderState *state);
|
||||||
|
|
||||||
INLINE int add_geom(Geom *geom, const RenderState *state = RenderState::make_empty());
|
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_geom(int n);
|
||||||
INLINE void remove_all_geoms();
|
INLINE void remove_all_geoms();
|
||||||
|
|
||||||
@ -118,6 +121,7 @@ private:
|
|||||||
static TypeHandle _type_handle;
|
static TypeHandle _type_handle;
|
||||||
|
|
||||||
friend class PandaNode::Children;
|
friend class PandaNode::Children;
|
||||||
|
friend class qpGeomTransformer;
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "qpgeomNode.I"
|
#include "qpgeomNode.I"
|
||||||
|
@ -159,6 +159,7 @@ fail() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE bool qpNodePath::
|
INLINE bool qpNodePath::
|
||||||
is_empty() const {
|
is_empty() const {
|
||||||
|
uncollapse_head();
|
||||||
return (_head == (qpNodePathComponent *)NULL);
|
return (_head == (qpNodePathComponent *)NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,6 +273,7 @@ attach_new_node(const string &name, int sort) const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE void qpNodePath::
|
INLINE void qpNodePath::
|
||||||
output(ostream &out) const {
|
output(ostream &out) const {
|
||||||
|
uncollapse_head();
|
||||||
if (_head == (qpNodePathComponent *)NULL) {
|
if (_head == (qpNodePathComponent *)NULL) {
|
||||||
out << "(empty)";
|
out << "(empty)";
|
||||||
} else {
|
} else {
|
||||||
@ -1113,6 +1115,9 @@ operator < (const qpNodePath &other) const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE int qpNodePath::
|
INLINE int qpNodePath::
|
||||||
compare_to(const qpNodePath &other) const {
|
compare_to(const qpNodePath &other) const {
|
||||||
|
uncollapse_head();
|
||||||
|
other.uncollapse_head();
|
||||||
|
|
||||||
// Nowadays, the NodePathComponents at the head are pointerwise
|
// Nowadays, the NodePathComponents at the head are pointerwise
|
||||||
// equivalent if and only iff the NodePaths are equivalent. So we
|
// equivalent if and only iff the NodePaths are equivalent. So we
|
||||||
// only have to compare pointers.
|
// only have to compare pointers.
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include "plist.h"
|
#include "plist.h"
|
||||||
#include "boundingSphere.h"
|
#include "boundingSphere.h"
|
||||||
#include "qpgeomNode.h"
|
#include "qpgeomNode.h"
|
||||||
|
#include "qpsceneGraphReducer.h"
|
||||||
|
|
||||||
// stack seems to overflow on Intel C++ at 7000. If we need more than
|
// stack seems to overflow on Intel C++ at 7000. If we need more than
|
||||||
// 7000, need to increase stack size.
|
// 7000, need to increase stack size.
|
||||||
@ -2403,10 +2404,8 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point) {
|
|||||||
int qpNodePath::
|
int qpNodePath::
|
||||||
flatten_light() {
|
flatten_light() {
|
||||||
nassertr(!is_empty(), 0);
|
nassertr(!is_empty(), 0);
|
||||||
/*
|
qpSceneGraphReducer gr;
|
||||||
SceneGraphReducer gr(_graph_type);
|
gr.apply_attribs(node());
|
||||||
gr.apply_transitions(arc());
|
|
||||||
*/
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2436,17 +2435,13 @@ flatten_light() {
|
|||||||
// The return value is the number of arcs removed.
|
// The return value is the number of arcs removed.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
int qpNodePath::
|
int qpNodePath::
|
||||||
flatten_medium(int max_children) {
|
flatten_medium() {
|
||||||
nassertr(!is_empty(), 0);
|
nassertr(!is_empty(), 0);
|
||||||
/*
|
qpSceneGraphReducer gr;
|
||||||
SceneGraphReducer gr(_graph_type);
|
gr.apply_attribs(node());
|
||||||
gr.set_max_children(max_children);
|
|
||||||
gr.apply_transitions(arc());
|
|
||||||
int num_removed = gr.flatten(node(), false);
|
int num_removed = gr.flatten(node(), false);
|
||||||
|
|
||||||
return num_removed;
|
return num_removed;
|
||||||
*/
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -2467,17 +2462,13 @@ flatten_medium(int max_children) {
|
|||||||
// because of less-effective culling.
|
// because of less-effective culling.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
int qpNodePath::
|
int qpNodePath::
|
||||||
flatten_strong(int max_children) {
|
flatten_strong() {
|
||||||
nassertr(!is_empty(), 0);
|
nassertr(!is_empty(), 0);
|
||||||
/*
|
qpSceneGraphReducer gr;
|
||||||
SceneGraphReducer gr(_graph_type);
|
gr.apply_attribs(node());
|
||||||
gr.set_max_children(max_children);
|
|
||||||
gr.apply_transitions(arc());
|
|
||||||
int num_removed = gr.flatten(node(), true);
|
int num_removed = gr.flatten(node(), true);
|
||||||
|
|
||||||
return num_removed;
|
return num_removed;
|
||||||
*/
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
@ -477,8 +477,8 @@ PUBLISHED:
|
|||||||
bool calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point);
|
bool calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point);
|
||||||
|
|
||||||
int flatten_light();
|
int flatten_light();
|
||||||
int flatten_medium(int max_children = 1);
|
int flatten_medium();
|
||||||
int flatten_strong(int max_children = 1);
|
int flatten_strong();
|
||||||
|
|
||||||
bool write_bam_file(const string &filename) const;
|
bool write_bam_file(const string &filename) const;
|
||||||
|
|
||||||
|
@ -72,8 +72,7 @@ RenderEffect::
|
|||||||
// Access: Public, Virtual
|
// Access: Public, Virtual
|
||||||
// Description: Returns true if it is generally safe to transform
|
// Description: Returns true if it is generally safe to transform
|
||||||
// this particular kind of RenderEffect by calling the
|
// this particular kind of RenderEffect by calling the
|
||||||
// xform() method, false otherwise. For instance, it's
|
// xform() method, false otherwise.
|
||||||
// usually a bad idea to attempt to xform a Character.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool RenderEffect::
|
bool RenderEffect::
|
||||||
safe_to_transform() const {
|
safe_to_transform() const {
|
||||||
@ -89,7 +88,7 @@ safe_to_transform() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool RenderEffect::
|
bool RenderEffect::
|
||||||
safe_to_combine() const {
|
safe_to_combine() const {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
@ -66,21 +66,27 @@ output(ostream &out) const {
|
|||||||
switch (get_mode()) {
|
switch (get_mode()) {
|
||||||
case M_none:
|
case M_none:
|
||||||
out << "none";
|
out << "none";
|
||||||
|
break;
|
||||||
|
|
||||||
case M_alpha:
|
case M_alpha:
|
||||||
out << "alpha";
|
out << "alpha";
|
||||||
|
break;
|
||||||
|
|
||||||
case M_alpha_sorted:
|
case M_alpha_sorted:
|
||||||
out << "alpha sorted";
|
out << "alpha sorted";
|
||||||
|
break;
|
||||||
|
|
||||||
case M_multisample:
|
case M_multisample:
|
||||||
out << "multisample";
|
out << "multisample";
|
||||||
|
break;
|
||||||
|
|
||||||
case M_multisample_mask:
|
case M_multisample_mask:
|
||||||
out << "multisample mask";
|
out << "multisample mask";
|
||||||
|
break;
|
||||||
|
|
||||||
case M_binary:
|
case M_binary:
|
||||||
out << "binary";
|
out << "binary";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "config_pgui.h"
|
#include "config_pgui.h"
|
||||||
|
|
||||||
#include "pandaNode.h"
|
#include "pandaNode.h"
|
||||||
|
#include "qpsceneGraphReducer.h"
|
||||||
#include "throw_event.h"
|
#include "throw_event.h"
|
||||||
#include "string_utils.h"
|
#include "string_utils.h"
|
||||||
#include "qpnodePath.h"
|
#include "qpnodePath.h"
|
||||||
@ -122,11 +123,9 @@ xform(const LMatrix4f &mat) {
|
|||||||
// Apply the matrix to the previous transform.
|
// Apply the matrix to the previous transform.
|
||||||
node->set_transform(node->get_transform()->compose(TransformState::make_mat(mat)));
|
node->set_transform(node->get_transform()->compose(TransformState::make_mat(mat)));
|
||||||
|
|
||||||
/*
|
|
||||||
// Now flatten the transform into the subgraph.
|
// Now flatten the transform into the subgraph.
|
||||||
SceneGraphReducer gr;
|
qpSceneGraphReducer gr;
|
||||||
gr.apply_transitions(arc);
|
gr.apply_attribs(node);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transform the frame style too.
|
// Transform the frame style too.
|
||||||
|
@ -28,9 +28,9 @@
|
|||||||
template<class CycleDataType>
|
template<class CycleDataType>
|
||||||
INLINE CycleDataReader<CycleDataType>::
|
INLINE CycleDataReader<CycleDataType>::
|
||||||
CycleDataReader(const PipelineCycler<CycleDataType> &cycler) :
|
CycleDataReader(const PipelineCycler<CycleDataType> &cycler) :
|
||||||
_cycler(cycler)
|
_cycler(&cycler)
|
||||||
{
|
{
|
||||||
_pointer = _cycler.read();
|
_pointer = _cycler->read();
|
||||||
_write_pointer = (CycleDataType *)NULL;
|
_write_pointer = (CycleDataType *)NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,10 +47,29 @@ CycleDataReader(const CycleDataReader<CycleDataType> ©) :
|
|||||||
_write_pointer(copy._write_pointer)
|
_write_pointer(copy._write_pointer)
|
||||||
{
|
{
|
||||||
nassertv(_pointer != (const CycleDataType *)NULL);
|
nassertv(_pointer != (const CycleDataType *)NULL);
|
||||||
// We cannot copy-construct a CycleDataReader that has elevated
|
// We cannot copy a CycleDataReader that has elevated itself to a
|
||||||
// itself to a write pointer.
|
// write pointer.
|
||||||
nassertv(_write_pointer == (const CycleDataType *)NULL);
|
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
|
// If the _write_pointer is non-NULL, then someone called
|
||||||
// elevate_to_write() at some point, and we now actually hold a
|
// elevate_to_write() at some point, and we now actually hold a
|
||||||
// write pointer, not a read pointer.
|
// 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) {
|
} else if (_pointer != (CycleDataType *)NULL) {
|
||||||
_cycler.release_read(_pointer);
|
_cycler->release_read(_pointer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +99,7 @@ INLINE CycleDataReader<CycleDataType>::
|
|||||||
template<class CycleDataType>
|
template<class CycleDataType>
|
||||||
INLINE const CycleDataType *CycleDataReader<CycleDataType>::
|
INLINE const CycleDataType *CycleDataReader<CycleDataType>::
|
||||||
operator -> () const {
|
operator -> () const {
|
||||||
nassertr(_pointer != (const CycleDataType *)NULL, _cycler.cheat());
|
nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat());
|
||||||
return _pointer;
|
return _pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +112,7 @@ operator -> () const {
|
|||||||
template<class CycleDataType>
|
template<class CycleDataType>
|
||||||
INLINE CycleDataReader<CycleDataType>::
|
INLINE CycleDataReader<CycleDataType>::
|
||||||
operator const CycleDataType * () const {
|
operator const CycleDataType * () const {
|
||||||
nassertr(_pointer != (const CycleDataType *)NULL, _cycler.cheat());
|
nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat());
|
||||||
return _pointer;
|
return _pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +132,7 @@ take_pointer() {
|
|||||||
const CycleDataType *pointer = _pointer;
|
const CycleDataType *pointer = _pointer;
|
||||||
_pointer = (CycleDataType *)NULL;
|
_pointer = (CycleDataType *)NULL;
|
||||||
_write_pointer = (CycleDataType *)NULL;
|
_write_pointer = (CycleDataType *)NULL;
|
||||||
nassertr(pointer != (const CycleDataType *)NULL, _cycler.cheat());
|
nassertr(pointer != (const CycleDataType *)NULL, _cycler->cheat());
|
||||||
return pointer;
|
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)
|
// Function: CycleDataReader::Destructor (trivial)
|
||||||
// Access: Public
|
// Access: Public
|
||||||
|
@ -41,6 +41,7 @@ class CycleDataReader {
|
|||||||
public:
|
public:
|
||||||
INLINE CycleDataReader(const PipelineCycler<CycleDataType> &cycler);
|
INLINE CycleDataReader(const PipelineCycler<CycleDataType> &cycler);
|
||||||
INLINE CycleDataReader(const CycleDataReader<CycleDataType> ©);
|
INLINE CycleDataReader(const CycleDataReader<CycleDataType> ©);
|
||||||
|
INLINE void operator = (const CycleDataReader<CycleDataType> ©);
|
||||||
|
|
||||||
INLINE ~CycleDataReader();
|
INLINE ~CycleDataReader();
|
||||||
|
|
||||||
@ -53,7 +54,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
#ifdef DO_PIPELINING
|
#ifdef DO_PIPELINING
|
||||||
// This is the data stored for a real pipelining implementation.
|
// This is the data stored for a real pipelining implementation.
|
||||||
const PipelineCycler<CycleDataType> &_cycler;
|
const PipelineCycler<CycleDataType> *_cycler;
|
||||||
const CycleDataType *_pointer;
|
const CycleDataType *_pointer;
|
||||||
CycleDataType *_write_pointer;
|
CycleDataType *_write_pointer;
|
||||||
#else // !DO_PIPELINING
|
#else // !DO_PIPELINING
|
||||||
|
@ -28,9 +28,39 @@
|
|||||||
template<class CycleDataType>
|
template<class CycleDataType>
|
||||||
INLINE CycleDataWriter<CycleDataType>::
|
INLINE CycleDataWriter<CycleDataType>::
|
||||||
CycleDataWriter(PipelineCycler<CycleDataType> &cycler) :
|
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>::
|
INLINE CycleDataWriter<CycleDataType>::
|
||||||
CycleDataWriter(PipelineCycler<CycleDataType> &cycler,
|
CycleDataWriter(PipelineCycler<CycleDataType> &cycler,
|
||||||
CycleDataWriter<CycleDataType> &take_from) :
|
CycleDataWriter<CycleDataType> &take_from) :
|
||||||
_cycler(cycler),
|
_cycler(&cycler),
|
||||||
_pointer(take_from._pointer)
|
_pointer(take_from._pointer)
|
||||||
{
|
{
|
||||||
take_from._pointer = (CycleDataType *)NULL;
|
take_from._pointer = (CycleDataType *)NULL;
|
||||||
@ -64,9 +94,9 @@ template<class CycleDataType>
|
|||||||
INLINE CycleDataWriter<CycleDataType>::
|
INLINE CycleDataWriter<CycleDataType>::
|
||||||
CycleDataWriter(PipelineCycler<CycleDataType> &cycler,
|
CycleDataWriter(PipelineCycler<CycleDataType> &cycler,
|
||||||
CycleDataReader<CycleDataType> &take_from) :
|
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>::
|
INLINE CycleDataWriter<CycleDataType>::
|
||||||
~CycleDataWriter() {
|
~CycleDataWriter() {
|
||||||
if (_pointer != (CycleDataType *)NULL) {
|
if (_pointer != (CycleDataType *)NULL) {
|
||||||
_cycler.release_write(_pointer);
|
_cycler->release_write(_pointer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +121,7 @@ INLINE CycleDataWriter<CycleDataType>::
|
|||||||
template<class CycleDataType>
|
template<class CycleDataType>
|
||||||
INLINE CycleDataType *CycleDataWriter<CycleDataType>::
|
INLINE CycleDataType *CycleDataWriter<CycleDataType>::
|
||||||
operator -> () {
|
operator -> () {
|
||||||
nassertr(_pointer != (CycleDataType *)NULL, _cycler.cheat());
|
nassertr(_pointer != (CycleDataType *)NULL, _cycler->cheat());
|
||||||
return _pointer;
|
return _pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +134,7 @@ operator -> () {
|
|||||||
template<class CycleDataType>
|
template<class CycleDataType>
|
||||||
INLINE const CycleDataType *CycleDataWriter<CycleDataType>::
|
INLINE const CycleDataType *CycleDataWriter<CycleDataType>::
|
||||||
operator -> () const {
|
operator -> () const {
|
||||||
nassertr(_pointer != (CycleDataType *)NULL, _cycler.cheat());
|
nassertr(_pointer != (CycleDataType *)NULL, _cycler->cheat());
|
||||||
return _pointer;
|
return _pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +147,7 @@ operator -> () const {
|
|||||||
template<class CycleDataType>
|
template<class CycleDataType>
|
||||||
INLINE CycleDataWriter<CycleDataType>::
|
INLINE CycleDataWriter<CycleDataType>::
|
||||||
operator CycleDataType * () {
|
operator CycleDataType * () {
|
||||||
nassertr(_pointer != (CycleDataType *)NULL, _cycler.cheat());
|
nassertr(_pointer != (CycleDataType *)NULL, _cycler->cheat());
|
||||||
return _pointer;
|
return _pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +165,29 @@ CycleDataWriter(PipelineCycler<CycleDataType> &cycler) {
|
|||||||
_pointer = cycler.write();
|
_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)
|
// Function: CycleDataWriter::Constructor (trivial)
|
||||||
// Access: Public
|
// Access: Public
|
||||||
|
@ -40,6 +40,9 @@ template<class CycleDataType>
|
|||||||
class CycleDataWriter {
|
class CycleDataWriter {
|
||||||
public:
|
public:
|
||||||
INLINE CycleDataWriter(PipelineCycler<CycleDataType> &cycler);
|
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, CycleDataWriter<CycleDataType> &take_from);
|
||||||
INLINE CycleDataWriter(PipelineCycler<CycleDataType> &cycler, CycleDataReader<CycleDataType> &take_from);
|
INLINE CycleDataWriter(PipelineCycler<CycleDataType> &cycler, CycleDataReader<CycleDataType> &take_from);
|
||||||
|
|
||||||
@ -53,7 +56,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
#ifdef DO_PIPELINING
|
#ifdef DO_PIPELINING
|
||||||
// This is the data stored for a real pipelining implementation.
|
// This is the data stored for a real pipelining implementation.
|
||||||
PipelineCycler<CycleDataType> &_cycler;
|
PipelineCycler<CycleDataType> *_cycler;
|
||||||
CycleDataType *_pointer;
|
CycleDataType *_pointer;
|
||||||
#else // !DO_PIPELINING
|
#else // !DO_PIPELINING
|
||||||
// This is all we need for the trivial, do-nothing implementation.
|
// 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);
|
render.attach_new_node(camera);
|
||||||
camera->set_scene(render);
|
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.
|
// Set up a data graph for tracking user input.
|
||||||
PT(PandaNode) data_root = new PandaNode("data_root");
|
PT(PandaNode) data_root = new PandaNode("data_root");
|
||||||
PandaNode *mouse = setup_mouse(data_root, window);
|
PandaNode *mouse = setup_mouse(data_root, window);
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "cullBinAttrib.h"
|
#include "cullBinAttrib.h"
|
||||||
#include "textureAttrib.h"
|
#include "textureAttrib.h"
|
||||||
#include "transparencyAttrib.h"
|
#include "transparencyAttrib.h"
|
||||||
|
#include "qpsceneGraphReducer.h"
|
||||||
#include "indent.h"
|
#include "indent.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -362,11 +363,9 @@ generate() {
|
|||||||
// applying them to the vertices.
|
// applying them to the vertices.
|
||||||
|
|
||||||
if (text_flatten) {
|
if (text_flatten) {
|
||||||
/* ****
|
qpSceneGraphReducer gr;
|
||||||
SceneGraphReducer gr(RenderRelation::get_class_type());
|
gr.apply_attribs(root);
|
||||||
gr.apply_transitions(root_arc);
|
|
||||||
gr.flatten(root, true);
|
gr.flatten(root, true);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user