several pgraph refinements

This commit is contained in:
David Rose 2002-03-20 23:18:28 +00:00
parent ec278a4f0f
commit d210511b8b
38 changed files with 313 additions and 231 deletions

View File

@ -281,8 +281,7 @@ do_cull(CullHandler *cull_handler, const qpNodePath &camera,
}
}
trav.traverse(scene.node());
trav.traverse(scene);
}
////////////////////////////////////////////////////////////////////

View File

@ -104,6 +104,10 @@ BoundingVolume *BoundedObject::
recompute_bound() {
CDWriter cdata(_cycler);
switch (cdata->_bound_type) {
case BVT_static:
// Don't change it if it's a static volume.
break;
case BVT_dynamic_sphere:
cdata->_bound = new BoundingSphere;
break;

View File

@ -45,7 +45,7 @@ class Filename;
// common scene graph files.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA BamFile {
public:
PUBLISHED:
BamFile();
~BamFile();

View File

@ -41,7 +41,7 @@
materialAttrib.I materialAttrib.h \
qpmodelNode.I qpmodelNode.h \
qpmodelRoot.I qpmodelRoot.h \
qpnodePath.I qpnodePath.h \
qpnodePath.I qpnodePath.h qpnodePath.cxx \
qpnodePathCollection.I qpnodePathCollection.h \
qpnodePathComponent.I qpnodePathComponent.h \
qpnodePathLerps.h \

View File

@ -23,11 +23,13 @@
// Description:
////////////////////////////////////////////////////////////////////
INLINE CullTraverserData::
CullTraverserData(const TransformState *render_transform,
CullTraverserData(const qpNodePath &start,
const TransformState *render_transform,
const TransformState *net_transform,
const RenderState *state,
GeometricBoundingVolume *view_frustum,
GeometricBoundingVolume *guard_band) :
_node_path(start),
_render_transform(render_transform),
_net_transform(net_transform),
_state(state),
@ -37,32 +39,42 @@ CullTraverserData(const TransformState *render_transform,
}
////////////////////////////////////////////////////////////////////
// Function: CullTraverserData::Copy Constructor
// Function: CullTraverserData::Constructor
// Access: Public
// Description:
// Description: This constructor creates a CullTraverserData object
// that reflects the next node down in the traversal.
////////////////////////////////////////////////////////////////////
INLINE CullTraverserData::
CullTraverserData(const CullTraverserData &copy) :
_render_transform(copy._render_transform),
_net_transform(copy._net_transform),
_state(copy._state),
_view_frustum(copy._view_frustum),
_guard_band(copy._guard_band)
CullTraverserData(const CullTraverserData &parent, PandaNode *child) :
_node_path(parent._node_path, child),
_render_transform(parent._render_transform),
_net_transform(parent._net_transform),
_state(parent._state),
_view_frustum(parent._view_frustum),
_guard_band(parent._guard_band)
{
}
////////////////////////////////////////////////////////////////////
// Function: CullTraverserData::Copy Constructor
// Access: Private
// Description: Do not copy CullTraverserData objects.
////////////////////////////////////////////////////////////////////
INLINE CullTraverserData::
CullTraverserData(const CullTraverserData &copy) :
_node_path(qpNodePath())
{
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: CullTraverserData::Copy Assignment Operator
// Access: Public
// Description:
// Access: Private
// Description: Do not copy CullTraverserData objects.
////////////////////////////////////////////////////////////////////
INLINE void CullTraverserData::
operator = (const CullTraverserData &copy) {
_render_transform = copy._render_transform;
_net_transform = copy._net_transform;
_state = copy._state;
_view_frustum = copy._view_frustum;
_guard_band = copy._guard_band;
nassertv(false);
}
////////////////////////////////////////////////////////////////////
@ -74,18 +86,33 @@ INLINE CullTraverserData::
~CullTraverserData() {
}
////////////////////////////////////////////////////////////////////
// Function: CullTraverserData::node
// Access: Public
// Description: Returns the node traversed to so far.
////////////////////////////////////////////////////////////////////
INLINE PandaNode *CullTraverserData::
node() const {
return _node_path.node();
}
////////////////////////////////////////////////////////////////////
// Function: CullTraverserData::is_in_view
// Access: Public
// Description: Returns true if the node is within the view frustum,
// false otherwise. If the node's bounding volume falls
// completely within the view frustum, this will also
// reset the view frustum pointer, saving some work for
// future nodes.
// Description: Returns true if the current node is within the view
// frustum, false otherwise. If the node's bounding
// volume falls completely within the view frustum, this
// will also reset the view frustum pointer, saving some
// work for future nodes.
////////////////////////////////////////////////////////////////////
INLINE bool CullTraverserData::
is_in_view(PandaNode *node, const DrawMask &camera_mask) {
if ((node->get_draw_mask() & camera_mask).is_zero()) {
is_in_view(const DrawMask &camera_mask) {
if (node()->get_transform()->is_invalid()) {
// If the transform is invalid, forget it.
return false;
}
if ((node()->get_draw_mask() & camera_mask).is_zero()) {
// If there are no draw bits in common with the camera, the node
// is out.
return false;
@ -98,5 +125,5 @@ is_in_view(PandaNode *node, const DrawMask &camera_mask) {
}
// Otherwise, compare the bounding volume to the frustum.
return is_in_view_impl(node);
return is_in_view_impl();
}

View File

@ -28,13 +28,13 @@
////////////////////////////////////////////////////////////////////
// Function: CullTraverserData::apply_transform_and_state
// Access: Public
// Description: Applies the transform and state from the indicated
// Description: Applies the transform and state from the current
// node onto the current data. This also evaluates
// billboards, etc.
////////////////////////////////////////////////////////////////////
void CullTraverserData::
apply_transform_and_state(qpCullTraverser *trav, PandaNode *node) {
const TransformState *node_transform = node->get_transform();
apply_transform_and_state(qpCullTraverser *trav) {
const TransformState *node_transform = node()->get_transform();
if (!node_transform->is_identity()) {
_render_transform = _render_transform->compose(node_transform);
_net_transform = _net_transform->compose(node_transform);
@ -69,9 +69,9 @@ apply_transform_and_state(qpCullTraverser *trav, PandaNode *node) {
}
}
_state = _state->compose(node->get_state());
_state = _state->compose(node()->get_state());
const RenderEffects *node_effects = node->get_effects();
const RenderEffects *node_effects = node()->get_effects();
const BillboardEffect *billboard = node_effects->get_billboard();
if (billboard != (const BillboardEffect *)NULL) {
// Got to apply a billboard transform here.
@ -94,11 +94,11 @@ apply_transform_and_state(qpCullTraverser *trav, PandaNode *node) {
// Description: The private implementation of is_in_view().
////////////////////////////////////////////////////////////////////
bool CullTraverserData::
is_in_view_impl(PandaNode *node) {
is_in_view_impl() {
// By the time we get here, we know we have a viewing frustum.
nassertr(_view_frustum != (GeometricBoundingVolume *)NULL, true);
const BoundingVolume &node_volume = node->get_bound();
const BoundingVolume &node_volume = node()->get_bound();
nassertr(node_volume.is_of_type(GeometricBoundingVolume::get_class_type()), false);
const GeometricBoundingVolume *node_gbv =
DCAST(GeometricBoundingVolume, &node_volume);
@ -123,7 +123,7 @@ is_in_view_impl(PandaNode *node) {
_view_frustum = (GeometricBoundingVolume *)NULL;
} else {
if (node->is_final()) {
if (node()->is_final()) {
// The bounding volume is partially, but not completely,
// within the viewing frustum. Normally we'd keep testing
// child bounding volumes as we continue down. But this node

View File

@ -21,6 +21,7 @@
#include "pandabase.h"
#include "workingNodePath.h"
#include "renderState.h"
#include "transformState.h"
#include "geometricBoundingVolume.h"
@ -46,18 +47,28 @@ class qpCullTraverser;
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA CullTraverserData {
public:
INLINE CullTraverserData(const TransformState *render_transform,
INLINE CullTraverserData(const qpNodePath &start,
const TransformState *render_transform,
const TransformState *net_transform,
const RenderState *state,
GeometricBoundingVolume *view_frustum,
GeometricBoundingVolume *guard_band);
INLINE CullTraverserData(const CullTraverserData &parent,
PandaNode *child);
private:
INLINE CullTraverserData(const CullTraverserData &copy);
INLINE void operator = (const CullTraverserData &copy);
INLINE void operator = (const CullTraverserData &copy);
public:
INLINE ~CullTraverserData();
INLINE bool is_in_view(PandaNode *node, const DrawMask &camera_mask);
void apply_transform_and_state(qpCullTraverser *trav, PandaNode *node);
INLINE PandaNode *node() const;
INLINE bool is_in_view(const DrawMask &camera_mask);
void apply_transform_and_state(qpCullTraverser *trav);
WorkingNodePath _node_path;
CPT(TransformState) _render_transform;
CPT(TransformState) _net_transform;
CPT(RenderState) _state;
@ -65,7 +76,7 @@ public:
PT(GeometricBoundingVolume) _guard_band;
private:
bool is_in_view_impl(PandaNode *node);
bool is_in_view_impl();
static CPT(RenderState) get_fake_view_frustum_cull_effect();
};

View File

@ -739,7 +739,7 @@ get_bound() const {
////////////////////////////////////////////////////////////////////
INLINE const BoundingVolume &PandaNode::
get_internal_bound() const {
if (_internal_bound.is_bound_stale()) {
if (is_bound_stale() || _internal_bound.is_bound_stale()) {
((PandaNode *)this)->recompute_internal_bound();
}
return _internal_bound.get_bound();

View File

@ -1157,17 +1157,21 @@ propagate_stale_bound() {
////////////////////////////////////////////////////////////////////
BoundingVolume *PandaNode::
recompute_bound() {
// First, get ourselves a fresh, empty bounding volume.
// Get the internal bound before we do anything else, since the
// is_bound_stale() flag may also apply to this.
const BoundingVolume *internal_bound = &get_internal_bound();
// Now, get ourselves a fresh, empty bounding volume. This will
// reset the is_bound_stale() flag if it was set.
BoundingVolume *bound = BoundedObject::recompute_bound();
nassertr(bound != (BoundingVolume*)NULL, bound);
// Now actually compute the bounding volume by putting it around all
// of our child bounding volumes.
pvector<const BoundingVolume *> child_volumes;
// It goes around this node's internal bounding volume . . .
child_volumes.push_back(&get_internal_bound());
child_volumes.push_back(internal_bound);
CDReader cdata(_cycler);
Down::const_iterator di;

View File

@ -10,7 +10,6 @@
#include "materialAttrib.cxx"
#include "qpmodelNode.cxx"
#include "qpmodelRoot.cxx"
#include "qpnodePath.cxx"
#include "qpnodePathCollection.cxx"
#include "qpnodePathComponent.cxx"
#include "qpnodePathLerps.cxx"

View File

@ -65,44 +65,39 @@ qpCullTraverser(const qpCullTraverser &copy) :
// Description: Begins the traversal from the indicated node.
////////////////////////////////////////////////////////////////////
void qpCullTraverser::
traverse(PandaNode *root) {
traverse(qpNodePath &root) {
nassertv(_cull_handler != (CullHandler *)NULL);
CullTraverserData data(_render_transform, TransformState::make_identity(),
CullTraverserData data(root,
_render_transform, TransformState::make_identity(),
_initial_state, _view_frustum, _guard_band);
traverse(root, data);
traverse(data);
}
////////////////////////////////////////////////////////////////////
// Function: qpCullTraverser::traverse
// Access: Public
// Description: Traverses from the indicated node with the given
// data, which has not yet been converted into the
// node's space.
// Description: Traverses from the next node with the given
// data, which has been constructed with the node but
// has not yet been converted into the node's space.
////////////////////////////////////////////////////////////////////
void qpCullTraverser::
traverse(PandaNode *node, const CullTraverserData &data) {
traverse(CullTraverserData &data) {
// Most nodes will have no transform or state, and will not
// contain decals or require a special cull callback. As an
// optimization, we should tag nodes with these properties as
// being "fancy", and skip this processing for non-fancy nodes.
if (data.is_in_view(_camera_mask)) {
data.apply_transform_and_state(this);
if (node->get_transform()->is_invalid()) {
// If the transform is invalid, forget it.
return;
}
CullTraverserData next_data(data);
if (next_data.is_in_view(node, _camera_mask)) {
next_data.apply_transform_and_state(this, node);
PandaNode *node = data.node();
if (node->has_cull_callback()) {
if (!node->cull_callback(this, next_data)) {
if (!node->cull_callback(this, data)) {
return;
}
}
traverse_below(node, next_data);
traverse_below(data);
}
}
@ -114,10 +109,11 @@ traverse(PandaNode *node, const CullTraverserData &data) {
// node's space.
////////////////////////////////////////////////////////////////////
void qpCullTraverser::
traverse_below(PandaNode *node, const CullTraverserData &data) {
traverse_below(const CullTraverserData &data) {
PandaNode *node = data.node();
const RenderEffects *node_effects = node->get_effects();
if (node_effects->has_decal()) {
start_decal(node, data);
start_decal(data);
} else {
if (node->is_geom_node()) {
@ -139,13 +135,15 @@ traverse_below(PandaNode *node, const CullTraverserData &data) {
if (node->has_selective_visibility()) {
int i = node->get_first_visible_child();
while (i < num_children) {
traverse(node->get_child(i), data);
CullTraverserData next_data(data, node->get_child(i));
traverse(next_data);
i = node->get_next_visible_child(i);
}
} else {
for (int i = 0; i < num_children; i++) {
traverse(node->get_child(i), data);
CullTraverserData next_data(data, node->get_child(i));
traverse(next_data);
}
}
}
@ -159,7 +157,8 @@ traverse_below(PandaNode *node, const CullTraverserData &data) {
// to find all the decal geoms.
////////////////////////////////////////////////////////////////////
void qpCullTraverser::
start_decal(PandaNode *node, const CullTraverserData &data) {
start_decal(const CullTraverserData &data) {
PandaNode *node = data.node();
if (!node->is_geom_node()) {
pgraph_cat.error()
<< "DecalEffect applied to " << *node << ", not a GeomNode.\n";
@ -179,13 +178,15 @@ start_decal(PandaNode *node, const CullTraverserData &data) {
if (node->has_selective_visibility()) {
int i = node->get_first_visible_child();
while (i < num_children) {
decals = r_get_decals(cr.get_child(i), data, decals);
CullTraverserData next_data(data, cr.get_child(i));
decals = r_get_decals(next_data, decals);
i = node->get_next_visible_child(i);
}
} else {
for (int i = num_children - 1; i >= 0; i--) {
decals = r_get_decals(cr.get_child(i), data, decals);
CullTraverserData next_data(data, cr.get_child(i));
decals = r_get_decals(next_data, decals);
}
}
@ -219,30 +220,26 @@ start_decal(PandaNode *node, const CullTraverserData &data) {
// they were encountered in the scene graph).
////////////////////////////////////////////////////////////////////
CullableObject *qpCullTraverser::
r_get_decals(PandaNode *node, const CullTraverserData &data,
CullableObject *decals) {
if (node->get_transform()->is_invalid()) {
// If the transform is invalid, forget it.
return decals;
}
r_get_decals(CullTraverserData &data, CullableObject *decals) {
if (data.is_in_view(_camera_mask)) {
data.apply_transform_and_state(this);
CullTraverserData next_data(data);
if (next_data.is_in_view(node, _camera_mask)) {
next_data.apply_transform_and_state(this, node);
PandaNode *node = data.node();
// First, visit all of the node's children.
PandaNode::Children cr = node->get_children();
int num_children = cr.get_num_children();
int num_children = node->get_num_children();
if (node->has_selective_visibility()) {
int i = node->get_first_visible_child();
while (i < num_children) {
decals = r_get_decals(cr.get_child(i), next_data, decals);
CullTraverserData next_data(data, node->get_child(i));
decals = r_get_decals(next_data, decals);
i = node->get_next_visible_child(i);
}
} else {
for (int i = num_children - 1; i >= 0; i--) {
decals = r_get_decals(cr.get_child(i), next_data, decals);
CullTraverserData next_data(data, node->get_child(i));
decals = r_get_decals(next_data, decals);
}
}
@ -252,7 +249,7 @@ r_get_decals(PandaNode *node, const CullTraverserData &data,
int num_geoms = geom_node->get_num_geoms();
for (int i = num_geoms - 1; i >= 0; i--) {
decals = new CullableObject(next_data, geom_node, i, decals);
decals = new CullableObject(data, geom_node, i, decals);
}
}
}

View File

@ -32,6 +32,7 @@ class PandaNode;
class CullHandler;
class CullTraverserData;
class CullableObject;
class qpNodePath;
////////////////////////////////////////////////////////////////////
// Class : CullTraverser
@ -67,14 +68,13 @@ public:
INLINE void set_cull_handler(CullHandler *cull_handler);
INLINE CullHandler *get_cull_handler() const;
void traverse(PandaNode *root);
void traverse(PandaNode *node, const CullTraverserData &data);
void traverse_below(PandaNode *node, const CullTraverserData &data);
void traverse(qpNodePath &root);
void traverse(CullTraverserData &data);
void traverse_below(const CullTraverserData &data);
private:
void start_decal(PandaNode *node, const CullTraverserData &data);
CullableObject *r_get_decals(PandaNode *node,
const CullTraverserData &data,
void start_decal(const CullTraverserData &data);
CullableObject *r_get_decals(CullTraverserData &data,
CullableObject *decals);
CPT(RenderState) _initial_state;

View File

@ -235,7 +235,7 @@ write_geoms(ostream &out, int indent_level) const {
for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
const GeomEntry &entry = (*gi);
indent(out, indent_level + 2)
<< *entry._geom << " (" << *entry._state << ")\n";
<< *entry._geom << " " << *entry._state << "\n";
}
}
@ -253,7 +253,7 @@ write_verbose(ostream &out, int indent_level) const {
for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
const GeomEntry &entry = (*gi);
indent(out, indent_level + 2)
<< *entry._geom << " (" << *entry._state << ")\n";
<< *entry._geom << " " << *entry._state << "\n";
entry._geom->write_verbose(out, indent_level + 4);
}
}

View File

@ -63,5 +63,8 @@ operator < (const qpGeomTransformer::SourceTexCoords &other) const {
////////////////////////////////////////////////////////////////////
INLINE bool qpGeomTransformer::SourceColors::
operator < (const qpGeomTransformer::SourceColors &other) const {
if (_colors != other._colors) {
return _colors < other._colors;
}
return (_scale.compare_to(other._scale) < 0);
}

View File

@ -296,6 +296,7 @@ transform_colors(Geom *geom, const LVecBase4f &scale) {
// transformed this array?
SourceColors sc;
sc._scale = scale;
sc._colors = colors;
PTA_Colorf &new_colors = _tcolors[sc];

View File

@ -68,6 +68,21 @@ make_copy() const {
return new qpLODNode(*this);
}
////////////////////////////////////////////////////////////////////
// Function: qpLODNode::safe_to_combine
// Access: Public, Virtual
// Description: Returns true if it is generally safe to combine this
// particular kind of PandaNode with other kinds of
// PandaNodes, adding children or whatever. For
// instance, an LODNode should not be combined with any
// other PandaNode, because its set of children is
// meaningful.
////////////////////////////////////////////////////////////////////
bool qpLODNode::
safe_to_combine() const {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: qpLODNode::xform
// Access: Public, Virtual

View File

@ -40,6 +40,7 @@ protected:
INLINE qpLODNode(const qpLODNode &copy);
public:
virtual PandaNode *make_copy() const;
virtual bool safe_to_combine() const;
virtual void xform(const LMatrix4f &mat);
virtual bool has_cull_callback() const;
virtual bool cull_callback(qpCullTraverser *trav, CullTraverserData &data);

View File

@ -65,6 +65,21 @@ safe_to_transform() const {
return !_preserve_transform;
}
////////////////////////////////////////////////////////////////////
// Function: qpModelNode::safe_to_combine
// Access: Public, Virtual
// Description: Returns true if it is generally safe to combine this
// particular kind of PandaNode with other kinds of
// PandaNodes, adding children or whatever. For
// instance, an LODNode should not be combined with any
// other PandaNode, because its set of children is
// meaningful.
////////////////////////////////////////////////////////////////////
bool qpModelNode::
safe_to_combine() const {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: qpModelNode::preserve_name
// Access: Public, Virtual

View File

@ -47,6 +47,7 @@ public:
virtual bool safe_to_flatten() const;
virtual bool safe_to_transform() const;
virtual bool safe_to_combine() const;
virtual bool preserve_name() const;
PUBLISHED:

View File

@ -597,34 +597,6 @@ get_mat() const {
return node()->get_transform()->get_mat();
}
////////////////////////////////////////////////////////////////////
// Function: qpNodePath::has_color_scale
// Access: Published
// Description: Returns true if a color scale has been applied
// to the referenced node, false otherwise. It is still
// possible that color at this node might have been
// scaled by an ancestor node.
////////////////////////////////////////////////////////////////////
INLINE bool qpNodePath::
has_color_scale() const {
nassertr(false, false);
return false;
}
////////////////////////////////////////////////////////////////////
// Function: qpNodePath::clear_color_scale
// Access: Published
// Description: Completely removes any color scale from the
// referenced node. This is preferable to simply
// setting the color scale to identity, as it also
// removes the overhead associated with having a color
// scale at all.
////////////////////////////////////////////////////////////////////
INLINE void qpNodePath::
clear_color_scale() {
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: qpNodePath::set_color_scale
// Access: Published

View File

@ -721,6 +721,35 @@ set_mat(const LMatrix4f &mat) {
set_transform(TransformState::make_mat(mat));
}
////////////////////////////////////////////////////////////////////
// Function: qpNodePath::has_color_scale
// Access: Published
// Description: Returns true if a color scale has been applied
// to the referenced node, false otherwise. It is still
// possible that color at this node might have been
// scaled by an ancestor node.
////////////////////////////////////////////////////////////////////
bool qpNodePath::
has_color_scale() const {
nassertr_always(!is_empty(), false);
return node()->has_attrib(ColorScaleAttrib::get_class_type());
}
////////////////////////////////////////////////////////////////////
// Function: qpNodePath::clear_color_scale
// Access: Published
// Description: Completely removes any color scale from the
// referenced node. This is preferable to simply
// setting the color scale to identity, as it also
// removes the overhead associated with having a color
// scale at all.
////////////////////////////////////////////////////////////////////
void qpNodePath::
clear_color_scale() {
nassertv_always(!is_empty());
node()->clear_attrib(ColorScaleAttrib::get_class_type());
}
////////////////////////////////////////////////////////////////////
// Function: qpNodePath::set_color_scale
// Access: Published

View File

@ -284,9 +284,8 @@ PUBLISHED:
INLINE bool has_mat() const;
INLINE const LMatrix4f &get_mat() const;
INLINE bool has_color_scale() const;
INLINE void clear_color_scale();
bool has_color_scale() const;
void clear_color_scale();
void set_color_scale(const LVecBase4f &scale);
INLINE void set_color_scale(float sx, float sy, float sz, float sa);
INLINE void set_sr(float sr);

View File

@ -23,8 +23,10 @@
#include "colorScaleAttrib.h"
#include "qpgeomNode.h"
#include "pointerTo.h"
#include "geom.h"
#include "indent.h"
#include "plist.h"
////////////////////////////////////////////////////////////////////
// Function: qpSceneGraphReducer::AccumulatedAttribs::write
@ -487,7 +489,9 @@ r_flatten(PandaNode *grandparent_node, PandaNode *parent_node,
// saved above is no longer accurate, so hereafter we must ask the
// node for its real child list.
if (combine_siblings && parent_node->get_num_children() >= 2) {
num_nodes += flatten_siblings(parent_node);
if (parent_node->safe_to_combine()) {
num_nodes += flatten_siblings(parent_node);
}
}
if (parent_node->get_num_children() == 1) {
@ -646,7 +650,7 @@ consider_child(PandaNode *grandparent_node, PandaNode *parent_node,
}
////////////////////////////////////////////////////////////////////
// Function: qpSceneGraphReducer::consider_siblings
// Function: qpSceneGraphReducer:c:onsider_siblings
// Access: Protected, Virtual
// Description: Decides whether or not the indicated sibling nodes
// should be collapsed into a single node or not.

View File

@ -32,6 +32,21 @@ make_copy() const {
return new CData(*this);
}
////////////////////////////////////////////////////////////////////
// Function: qpSequenceNode::safe_to_combine
// Access: Public, Virtual
// Description: Returns true if it is generally safe to combine this
// particular kind of PandaNode with other kinds of
// PandaNodes, adding children or whatever. For
// instance, an LODNode should not be combined with any
// other PandaNode, because its set of children is
// meaningful.
////////////////////////////////////////////////////////////////////
bool qpSequenceNode::
safe_to_combine() const {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: qpSequenceNode::CData::write_datagram
// Access: Public, Virtual

View File

@ -37,6 +37,7 @@ public:
qpSequenceNode(const qpSequenceNode &copy);
virtual PandaNode *make_copy() const;
virtual bool safe_to_combine() const;
virtual bool has_cull_callback() const;
virtual bool cull_callback(qpCullTraverser *trav, CullTraverserData &data);

View File

@ -70,3 +70,13 @@ get_node_path() const {
nassertr(result._head != (qpNodePathComponent *)NULL, qpNodePath::fail());
return result;
}
////////////////////////////////////////////////////////////////////
// Function: WorkingNodePath::node
// Access: Public
// Description: Returns the node traversed to so far.
////////////////////////////////////////////////////////////////////
INLINE PandaNode *WorkingNodePath::
node() const {
return _node;
}

View File

@ -53,6 +53,7 @@ public:
INLINE ~WorkingNodePath();
INLINE qpNodePath get_node_path() const;
INLINE PandaNode *node() const;
private:
PT(qpNodePathComponent) r_get_node_path() const;

View File

@ -23,6 +23,7 @@
#include "pandaNode.h"
#include "transparencyAttrib.h"
#include "pointerTo.h"
#include "qpnodePath.h"
#include "geomNode.h"
#include "transparencyProperty.h"
@ -168,16 +169,16 @@ generate_into(Node *node, const LVecBase4f &frame) {
// indicated size, and parents it to the indicated node,
// with a scene graph sort order of -1.
//
// The return value is the generated node, if any, or
// NULL if nothing is generated.
// The return value is the generated NodePath, if any,
// or an empty NodePath if nothing is generated.
////////////////////////////////////////////////////////////////////
PandaNode *PGFrameStyle::
generate_into(PandaNode *node, const LVecBase4f &frame) {
qpNodePath PGFrameStyle::
generate_into(const qpNodePath &parent, const LVecBase4f &frame) {
PT(PandaNode) new_node;
switch (_type) {
case T_none:
return (PandaNode *)NULL;
return qpNodePath();
case T_flat:
new_node = qpgenerate_flat_geom(frame);
@ -209,8 +210,7 @@ generate_into(PandaNode *node, const LVecBase4f &frame) {
}
// Adding the node to the parent keeps the reference count.
node->add_child(new_node);
return new_node;
return parent.attach_new_node(new_node);
}
////////////////////////////////////////////////////////////////////

View File

@ -27,6 +27,7 @@
class NodeRelation;
class Node;
class PandaNode;
class qpNodePath;
////////////////////////////////////////////////////////////////////
// Class : PGFrameStyle
@ -65,7 +66,7 @@ PUBLISHED:
public:
bool xform(const LMatrix4f &mat);
NodeRelation *generate_into(Node *node, const LVecBase4f &frame);
PandaNode *generate_into(PandaNode *node, const LVecBase4f &frame);
qpNodePath generate_into(const qpNodePath &parent, const LVecBase4f &frame);
private:
PT_Node generate_flat_geom(const LVecBase4f &frame);

View File

@ -186,10 +186,10 @@ setup(const string &label) {
PT(PandaNode) rollover = new PandaNode("rollover");
PT(PandaNode) inactive = new PandaNode("inactive");
get_state_def(S_ready)->add_child(ready);
get_state_def(S_depressed)->add_child(depressed);
get_state_def(S_rollover)->add_child(rollover);
get_state_def(S_inactive)->add_child(inactive);
get_state_def(S_ready).attach_new_node(ready);
get_state_def(S_depressed).attach_new_node(depressed);
get_state_def(S_rollover).attach_new_node(rollover);
get_state_def(S_inactive).attach_new_node(inactive);
ready->add_child(geom);
depressed->add_child(geom);

View File

@ -191,7 +191,7 @@ get_blink_rate() const {
// the cursor. You can attach suitable cursor geometry
// to this node.
////////////////////////////////////////////////////////////////////
INLINE PandaNode *qpPGEntry::
INLINE const qpNodePath &qpPGEntry::
get_cursor_def() {
return _cursor_def;
}
@ -204,7 +204,8 @@ get_cursor_def() {
////////////////////////////////////////////////////////////////////
INLINE void qpPGEntry::
clear_cursor_def() {
get_cursor_def()->remove_all_children();
_cursor_def.remove_node();
_cursor_def = _text_render_root.attach_new_node("cursor");
}
////////////////////////////////////////////////////////////////////

View File

@ -20,6 +20,7 @@
#include "pgMouseWatcherParameter.h"
#include "qpcullTraverser.h"
#include "cullTraverserData.h"
#include "throw_event.h"
#include "transformState.h"
#include "mouseWatcherParameter.h"
@ -50,10 +51,8 @@ qpPGEntry(const string &name) :
_blink_start = 0.0f;
_blink_rate = 1.0f;
_text_render_root = new PandaNode("text_root");
_current_text_node = (PandaNode *)NULL;
_cursor_def = new PandaNode("cursor");
_text_render_root->add_child(_cursor_def);
_text_render_root = qpNodePath("text_root");
_cursor_def = _text_render_root.attach_new_node("cursor");
_cursor_visible = true;
_cursor_keys_active = true;
@ -149,8 +148,8 @@ cull_callback(qpCullTraverser *trav, CullTraverserData &data) {
update_cursor();
// Now render the text.
nassertr(_text_render_root != (PandaNode *)NULL, true);
trav->traverse(_text_render_root, data);
CullTraverserData next_data(data, _text_render_root.node());
trav->traverse(next_data);
// Now continue to render everything else below this node.
return true;
@ -596,12 +595,12 @@ setup(float width, int num_lines) {
ls.set_color(0.0f, 0.0f, 0.0f, 1.0f);
ls.move_to(0.0f, 0.0f, -0.15f * line_height);
ls.draw_to(0.0f, 0.0f, 0.85f * line_height);
get_cursor_def()->add_child(ls.create());
get_cursor_def().attach_new_node(ls.create());
/*
// An underscore cursor would work too.
text_node->set_text("_");
get_cursor_def()->add_child(text_node->generate());
get_cursor_def().attach_new_node(text_node->generate());
*/
}
@ -782,11 +781,11 @@ update_text() {
line._left = _last_text_def->get_left();
}
if (_current_text_node != (PandaNode *)NULL) {
_text_render_root->remove_child(_current_text_node);
if (!_current_text.is_empty()) {
_current_text.remove_node();
}
_current_text_node = _last_text_def->generate();
_text_render_root->add_child(_current_text_node);
_current_text =
_text_render_root.attach_new_node(_last_text_def->generate());
_text_geom_stale = false;
_cursor_stale = true;
}
@ -824,7 +823,7 @@ update_cursor() {
float line_height = _last_text_def->get_line_height();
LVecBase3f trans(_ww_lines[row]._left + width, 0.0f, -line_height * row);
_cursor_def->set_transform(TransformState::make_pos(trans));
_cursor_def.set_pos(trans);
_cursor_stale = false;
}
@ -851,11 +850,9 @@ void qpPGEntry::
show_hide_cursor(bool visible) {
if (visible != _cursor_visible) {
if (visible) {
// Reveal the cursor.
_cursor_def->set_draw_mask(DrawMask::all_on());
_cursor_def.show();
} else {
// Hide the cursor.
_cursor_def->set_draw_mask(DrawMask::all_off());
_cursor_def.hide();
}
_cursor_visible = visible;
}

View File

@ -88,7 +88,7 @@ PUBLISHED:
INLINE void set_blink_rate(float blink_rate);
INLINE float get_blink_rate() const;
INLINE PandaNode *get_cursor_def();
INLINE const qpNodePath &get_cursor_def();
INLINE void clear_cursor_def();
INLINE void set_cursor_keys_active(bool flag);
@ -139,13 +139,12 @@ private:
typedef pvector< PT(qpTextNode) > TextDefs;
TextDefs _text_defs;
// This node is the root of the subgraph that renders both the text
// and the cursor.
PT(PandaNode) _text_render_root;
// This is the subgraph that renders both the text and the cursor.
qpNodePath _text_render_root;
// This is the node for rendering the actual text that is parented
// to the above node when the text is generated.
PT(PandaNode) _current_text_node;
qpNodePath _current_text;
qpTextNode *_last_text_def;
bool _text_geom_stale;
@ -163,7 +162,7 @@ private:
// This is the node that represents the cursor geometry. It is also
// attached to the above node, and is transformed around and/or
// hidden according to the cursor's position and blink state.
PandaNode *_cursor_def;
qpNodePath _cursor_def;
double _blink_start;
double _blink_rate;

View File

@ -28,6 +28,7 @@
#include "string_utils.h"
#include "qpnodePath.h"
#include "qpcullTraverser.h"
#include "cullTraverserData.h"
#ifdef HAVE_AUDIO
#include "audioSound.h"
@ -118,15 +119,13 @@ xform(const LMatrix4f &mat) {
// Transform the individual states and their frame styles.
StateDefs::iterator di;
for (di = _state_defs.begin(); di != _state_defs.end(); ++di) {
PandaNode *node = (*di)._node;
if (node != (PandaNode *)NULL) {
// Apply the matrix to the previous transform.
node->set_transform(node->get_transform()->compose(TransformState::make_mat(mat)));
qpNodePath &root = (*di)._root;
// Apply the matrix to the previous transform.
root.set_transform(root.get_transform()->compose(TransformState::make_mat(mat)));
// Now flatten the transform into the subgraph.
qpSceneGraphReducer gr;
gr.apply_attribs(node);
}
// Now flatten the transform into the subgraph.
qpSceneGraphReducer gr;
gr.apply_attribs(root.node());
// Transform the frame style too.
if ((*di)._frame_style.xform(mat)) {
@ -193,8 +192,9 @@ cull_callback(qpCullTraverser *trav, CullTraverserData &data) {
if (has_state_def(get_state())) {
// This item has a current state definition that we should use
// to render the item.
PandaNode *def = get_state_def(get_state());
trav->traverse(def, data);
qpNodePath &root = get_state_def(get_state());
CullTraverserData next_data(data, root.node());
trav->traverse(next_data);
}
// Now continue to render everything else below this node.
@ -223,9 +223,9 @@ recompute_internal_bound() {
// get_state_def() on each one, to ensure that the frames are
// updated correctly before we measure their bounding volumes.
for (int i = 0; i < (int)_state_defs.size(); i++) {
PandaNode *node = get_state_def(i);
if (node != (PandaNode *)NULL) {
child_volumes.push_back(&node->get_bound());
qpNodePath &root = get_state_def(i);
if (!root.is_empty()) {
child_volumes.push_back(&root.node()->get_bound());
}
}
@ -582,7 +582,7 @@ has_state_def(int state) const {
if (state < 0 || state >= (int)_state_defs.size()) {
return false;
}
return (_state_defs[state]._node != (PandaNode *)NULL);
return (!_state_defs[state]._root.is_empty());
}
////////////////////////////////////////////////////////////////////
@ -598,12 +598,8 @@ clear_state_def(int state) {
return;
}
PandaNode *node = _state_defs[state]._node;
if (node != (PandaNode *)NULL) {
node->remove_all_children();
}
_state_defs[state]._frame_node = (PandaNode *)NULL;
_state_defs[state]._root = qpNodePath();
_state_defs[state]._frame = qpNodePath();
_state_defs[state]._frame_stale = true;
mark_bound_stale();
@ -617,14 +613,14 @@ clear_state_def(int state) {
// indicated state. The first time this is called for a
// particular state index, it may create the Node.
////////////////////////////////////////////////////////////////////
PandaNode *qpPGItem::
qpNodePath &qpPGItem::
get_state_def(int state) {
nassertr(state >= 0 && state < 1000, (PandaNode *)NULL); // Sanity check.
nassertr(state >= 0 && state < 1000, get_state_def(0)); // Sanity check.
slot_state_def(state);
if (_state_defs[state]._node == (PandaNode *)NULL) {
if (_state_defs[state]._root.is_empty()) {
// Create a new node.
_state_defs[state]._node = new PandaNode("state_" + format_string(state));
_state_defs[state]._root = qpNodePath("state_" + format_string(state));
_state_defs[state]._frame_stale = true;
}
@ -632,7 +628,7 @@ get_state_def(int state) {
update_frame(state);
}
return _state_defs[state]._node;
return _state_defs[state]._root;
}
////////////////////////////////////////////////////////////////////
@ -641,16 +637,16 @@ get_state_def(int state) {
// Description: Parents an instance of the bottom node of the
// indicated NodePath to the indicated state index.
////////////////////////////////////////////////////////////////////
void qpPGItem::
qpNodePath qpPGItem::
instance_to_state_def(int state, const qpNodePath &path) {
if (path.is_empty()) {
// If the path is empty, quietly do nothing.
return;
// If the source is empty, quietly do nothing.
return qpNodePath();
}
get_state_def(state)->add_child(path.node());
mark_bound_stale();
return path.instance_to(get_state_def(state));
}
////////////////////////////////////////////////////////////////////
@ -677,8 +673,8 @@ void qpPGItem::
set_frame_style(int state, const PGFrameStyle &style) {
// Get the state def node, mainly to ensure that this state is
// slotted and listed as having been defined.
PandaNode *def = get_state_def(state);
nassertv(def != (PandaNode *)NULL);
qpNodePath &root = get_state_def(state);
nassertv(!root.is_empty());
_state_defs[state]._frame_style = style;
_state_defs[state]._frame_stale = true;
@ -799,13 +795,7 @@ void qpPGItem::
update_frame(int state) {
// First, remove the old frame geometry, if any.
if (state >= 0 && state < (int)_state_defs.size()) {
PandaNode *old_frame = _state_defs[state]._frame_node;
if (old_frame != (PandaNode *)NULL) {
PandaNode *node = _state_defs[state]._node;
nassertv(node != (PandaNode *)NULL);
node->remove_child(old_frame);
_state_defs[state]._frame_node = (PandaNode *)NULL;
}
_state_defs[state]._frame.remove_node();
}
// We must turn off the stale flag first, before we call
@ -815,10 +805,9 @@ update_frame(int state) {
// Now create new frame geometry.
if (has_frame()) {
PandaNode *node = get_state_def(state);
nassertv(node != (PandaNode *)NULL);
_state_defs[state]._frame_node =
_state_defs[state]._frame_style.generate_into(node, _frame);
qpNodePath &root = get_state_def(state);
_state_defs[state]._frame =
_state_defs[state]._frame_style.generate_into(root, _frame);
}
}
@ -834,14 +823,7 @@ mark_frames_stale() {
StateDefs::iterator di;
for (di = _state_defs.begin(); di != _state_defs.end(); ++di) {
// Remove the old frame, if any.
PandaNode *old_frame = (*di)._frame_node;
if (old_frame != (PandaNode *)NULL) {
PandaNode *node = (*di)._node;
nassertv(node != (PandaNode *)NULL);
node->remove_child(old_frame);
(*di)._frame_node = (PandaNode *)NULL;
}
(*di)._frame.remove_node();
(*di)._frame_stale = true;
}
mark_bound_stale();

View File

@ -25,6 +25,7 @@
#include "pgFrameStyle.h"
#include "pandaNode.h"
#include "qpnodePath.h"
#include "luse.h"
#include "pointerTo.h"
#include "qptextNode.h"
@ -34,7 +35,6 @@
class PGTop;
class MouseWatcherParameter;
class AudioSound;
class qpNodePath;
////////////////////////////////////////////////////////////////////
// Class : qpPGItem
@ -108,8 +108,8 @@ PUBLISHED:
int get_num_state_defs() const;
void clear_state_def(int state);
bool has_state_def(int state) const;
PandaNode *get_state_def(int state);
void instance_to_state_def(int state, const qpNodePath &chain);
qpNodePath &get_state_def(int state);
qpNodePath instance_to_state_def(int state, const qpNodePath &path);
PGFrameStyle get_frame_style(int state);
void set_frame_style(int state, const PGFrameStyle &style);
@ -171,9 +171,9 @@ private:
class StateDef {
public:
PT(PandaNode) _node;
qpNodePath _root;
PGFrameStyle _frame_style;
PT(PandaNode) _frame_node;
qpNodePath _frame;
bool _frame_stale;
};
typedef pvector<StateDef> StateDefs;

View File

@ -118,7 +118,7 @@ cull_callback(qpCullTraverser *trav, CullTraverserData &data) {
// PGTop node, for the convenience of PGItems to register themselves
// as they are drawn.
PGCullTraverser pg_trav(this, trav);
pg_trav.traverse_below(this, data);
pg_trav.traverse_below(data);
// We've taken care of the traversal, thank you.
return false;

View File

@ -34,7 +34,6 @@ qpPGWaitBar(const string &name) : qpPGItem(name)
_range = 100.0;
_value = 0.0;
_bar_state = -1;
_bar_node = (PandaNode *)NULL;
}
////////////////////////////////////////////////////////////////////
@ -58,7 +57,6 @@ qpPGWaitBar(const qpPGWaitBar &copy) :
_value(copy._value)
{
_bar_state = -1;
_bar_node = (PandaNode *)NULL;
}
////////////////////////////////////////////////////////////////////
@ -155,16 +153,12 @@ update() {
}
// Remove the old bar geometry, if any.
if (_bar_node != (PandaNode *)NULL) {
PandaNode *parent_node = _bar_node->get_parent(0);
parent_node->remove_child(_bar_node);
_bar_node = (PandaNode *)NULL;
}
_bar.remove_node();
// Now create new bar geometry.
if (_value != 0.0 && _range != 0.0) {
PandaNode *node = get_state_def(state);
nassertv(node != (PandaNode *)NULL);
qpNodePath &root = get_state_def(state);
nassertv(!root.is_empty());
PGFrameStyle style = get_frame_style(state);
const LVecBase4f &frame = get_frame();
@ -181,7 +175,7 @@ update() {
frac = max(min(frac, 1.0f), 0.0f);
bar_frame[1] = bar_frame[0] + frac * (bar_frame[1] - bar_frame[0]);
_bar_node = _bar_style.generate_into(node, bar_frame);
_bar = _bar_style.generate_into(root, bar_frame);
}
// Indicate that the bar is current for this state.

View File

@ -63,7 +63,7 @@ private:
float _range, _value;
int _bar_state;
PGFrameStyle _bar_style;
PT(PandaNode) _bar_node;
qpNodePath _bar;
public:
static TypeHandle get_class_type() {