dynamic TextFont; scene graph improvements to support this

This commit is contained in:
David Rose 2003-01-31 17:45:42 +00:00
parent 8e63f99ee2
commit 2fa7929b45
18 changed files with 1004 additions and 612 deletions

View File

@ -8,6 +8,7 @@
#define TARGET pgraph #define TARGET pgraph
#define SOURCES \ #define SOURCES \
accumulatedAttribs.I accumulatedAttribs.h \
alphaTestAttrib.I alphaTestAttrib.h \ alphaTestAttrib.I alphaTestAttrib.h \
ambientLight.I ambientLight.h \ ambientLight.I ambientLight.h \
bamFile.I bamFile.h \ bamFile.I bamFile.h \
@ -91,6 +92,7 @@
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
#define INCLUDED_SOURCES \ #define INCLUDED_SOURCES \
accumulatedAttribs.cxx \
alphaTestAttrib.cxx \ alphaTestAttrib.cxx \
ambientLight.cxx \ ambientLight.cxx \
bamFile.cxx \ bamFile.cxx \
@ -173,6 +175,7 @@
workingNodePath.cxx workingNodePath.cxx
#define INSTALL_HEADERS \ #define INSTALL_HEADERS \
accumulatedAttribs.I accumulatedAttribs.h \
alphaTestAttrib.I alphaTestAttrib.h \ alphaTestAttrib.I alphaTestAttrib.h \
ambientLight.I ambientLight.h \ ambientLight.I ambientLight.h \
bamFile.I bamFile.h \ bamFile.I bamFile.h \

View File

@ -0,0 +1,58 @@
// Filename: accumulatedAttribs.I
// Created by: drose (30Jan03)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: AccumulatedAttribs::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE AccumulatedAttribs::
AccumulatedAttribs() {
_transform = TransformState::make_identity();
_other = RenderState::make_empty();
}
////////////////////////////////////////////////////////////////////
// Function: AccumulatedAttribs::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE AccumulatedAttribs::
AccumulatedAttribs(const AccumulatedAttribs &copy) :
_transform(copy._transform),
_color(copy._color),
_color_scale(copy._color_scale),
_tex_matrix(copy._tex_matrix),
_other(copy._other)
{
}
////////////////////////////////////////////////////////////////////
// Function: AccumulatedAttribs::Copy Assignment
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void AccumulatedAttribs::
operator = (const AccumulatedAttribs &copy) {
_transform = copy._transform;
_color = copy._color;
_color_scale = copy._color_scale;
_tex_matrix = copy._tex_matrix;
_other = copy._other;
}

View File

@ -0,0 +1,190 @@
// Filename: accumulatedAttribs.cxx
// Created by: drose (30Jan03)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "accumulatedAttribs.h"
#include "sceneGraphReducer.h"
#include "geomTransformer.h"
#include "pandaNode.h"
#include "colorAttrib.h"
#include "colorScaleAttrib.h"
#include "texMatrixAttrib.h"
#include "config_pgraph.h"
////////////////////////////////////////////////////////////////////
// Function: AccumulatedAttribs::write
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void AccumulatedAttribs::
write(ostream &out, int attrib_types, int indent_level) const {
if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
_transform->write(out, indent_level);
}
if ((attrib_types & SceneGraphReducer::TT_color) != 0) {
if (_color == (const RenderAttrib *)NULL) {
indent(out, indent_level) << "no color\n";
} else {
_color->write(out, indent_level);
}
}
if ((attrib_types & SceneGraphReducer::TT_color_scale) != 0) {
if (_color_scale == (const RenderAttrib *)NULL) {
indent(out, indent_level) << "no color scale\n";
} else {
_color_scale->write(out, indent_level);
}
}
if ((attrib_types & SceneGraphReducer::TT_tex_matrix) != 0) {
if (_tex_matrix == (const RenderAttrib *)NULL) {
indent(out, indent_level) << "no tex matrix\n";
} else {
_tex_matrix->write(out, indent_level);
}
}
if ((attrib_types & SceneGraphReducer::TT_other) != 0) {
_other->write(out, indent_level);
}
}
////////////////////////////////////////////////////////////////////
// Function: AccumulatedAttribs::collect
// Access: Public
// Description: Collects the state and transform from the indicated
// node and adds it to the accumulator, removing it from
// the node.
////////////////////////////////////////////////////////////////////
void AccumulatedAttribs::
collect(PandaNode *node, int attrib_types) {
if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
// Collect the node's transform.
nassertv(_transform != (TransformState *)NULL);
_transform = _transform->compose(node->get_transform());
node->set_transform(TransformState::make_identity());
}
if ((attrib_types & SceneGraphReducer::TT_color) != 0) {
const RenderAttrib *node_attrib =
node->get_attrib(ColorAttrib::get_class_type());
if (node_attrib != (const RenderAttrib *)NULL) {
// The node has a color attribute; apply it.
if (_color == (const RenderAttrib *)NULL) {
_color = node_attrib;
} else {
_color = _color->compose(node_attrib);
}
node->clear_attrib(ColorAttrib::get_class_type());
}
}
if ((attrib_types & SceneGraphReducer::TT_color_scale) != 0) {
const RenderAttrib *node_attrib =
node->get_attrib(ColorScaleAttrib::get_class_type());
if (node_attrib != (const RenderAttrib *)NULL) {
// The node has a color scale attribute; apply it.
if (_color_scale == (const RenderAttrib *)NULL) {
_color_scale = node_attrib;
} else {
_color_scale = _color_scale->compose(node_attrib);
}
node->clear_attrib(ColorScaleAttrib::get_class_type());
}
}
if ((attrib_types & SceneGraphReducer::TT_tex_matrix) != 0) {
const RenderAttrib *node_attrib =
node->get_attrib(TexMatrixAttrib::get_class_type());
if (node_attrib != (const RenderAttrib *)NULL) {
// The node has a tex matrix attribute; apply it.
if (_tex_matrix == (const RenderAttrib *)NULL) {
_tex_matrix = node_attrib;
} else {
_tex_matrix = _tex_matrix->compose(node_attrib);
}
node->clear_attrib(TexMatrixAttrib::get_class_type());
}
}
if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
// Collect everything else.
nassertv(_other != (RenderState *)NULL);
_other = _other->compose(node->get_state());
node->set_state(RenderState::make_empty());
}
}
////////////////////////////////////////////////////////////////////
// Function: AccumulatedAttribs::apply_to_node
// Access: Public
// Description: Stores the indicated attributes in the node's
// transform and state information; does not attempt to
// apply the properties to the vertices. Clears the
// attributes from the accumulator for future
// traversals.
////////////////////////////////////////////////////////////////////
void AccumulatedAttribs::
apply_to_node(PandaNode *node, int attrib_types) {
if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
node->set_transform(_transform->compose(node->get_transform()));
_transform = TransformState::make_identity();
}
if ((attrib_types & SceneGraphReducer::TT_color) != 0) {
if (_color != (RenderAttrib *)NULL) {
const RenderAttrib *node_attrib =
node->get_attrib(ColorAttrib::get_class_type());
if (node_attrib != (RenderAttrib *)NULL) {
node->set_attrib(_color->compose(node_attrib));
} else {
node->set_attrib(_color);
}
_color = (RenderAttrib *)NULL;
}
}
if ((attrib_types & SceneGraphReducer::TT_color_scale) != 0) {
if (_color_scale != (RenderAttrib *)NULL) {
const RenderAttrib *node_attrib =
node->get_attrib(ColorScaleAttrib::get_class_type());
if (node_attrib != (RenderAttrib *)NULL) {
node->set_attrib(_color_scale->compose(node_attrib));
} else {
node->set_attrib(_color_scale);
}
_color_scale = (RenderAttrib *)NULL;
}
}
if ((attrib_types & SceneGraphReducer::TT_tex_matrix) != 0) {
if (_tex_matrix != (RenderAttrib *)NULL) {
const RenderAttrib *node_attrib =
node->get_attrib(TexMatrixAttrib::get_class_type());
if (node_attrib != (RenderAttrib *)NULL) {
node->set_attrib(_tex_matrix->compose(node_attrib));
} else {
node->set_attrib(_tex_matrix);
}
_tex_matrix = (RenderAttrib *)NULL;
}
}
if ((attrib_types & SceneGraphReducer::TT_other) != 0) {
node->set_state(_other->compose(node->get_state()));
_other = RenderState::make_empty();
}
}

View File

@ -0,0 +1,59 @@
// Filename: accumulatedAttribs.h
// Created by: drose (30Jan03)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef ACCUMULATEDATTRIBS_H
#define ACCUMULATEDATTRIBS_H
#include "pandabase.h"
#include "transformState.h"
#include "renderAttrib.h"
#include "renderState.h"
#include "pointerTo.h"
class PandaNode;
///////////////////////////////////////////////////////////////////
// Class : AccumulatedAttribs
// Description : This class is used by the SceneGraphReducer to
// maintain and accumulate the set of attributes we have
// encountered on each node that might eventually be
// applied to the vertices at the leaves.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA AccumulatedAttribs {
public:
INLINE AccumulatedAttribs();
INLINE AccumulatedAttribs(const AccumulatedAttribs &copy);
INLINE void operator = (const AccumulatedAttribs &copy);
void write(ostream &out, int attrib_types, int indent_level) const;
void collect(PandaNode *node, int attrib_types);
void apply_to_node(PandaNode *node, int attrib_types);
CPT(TransformState) _transform;
CPT(RenderAttrib) _color;
CPT(RenderAttrib) _color_scale;
CPT(RenderAttrib) _tex_matrix;
CPT(RenderState) _other;
};
#include "accumulatedAttribs.I"
#endif

View File

@ -18,6 +18,8 @@
#include "geomNode.h" #include "geomNode.h"
#include "geomTransformer.h" #include "geomTransformer.h"
#include "sceneGraphReducer.h"
#include "accumulatedAttribs.h"
#include "bamReader.h" #include "bamReader.h"
#include "bamWriter.h" #include "bamWriter.h"
#include "datagram.h" #include "datagram.h"
@ -154,6 +156,62 @@ make_copy() const {
return new GeomNode(*this); return new GeomNode(*this);
} }
////////////////////////////////////////////////////////////////////
// Function: GeomNode::apply_attribs_to_vertices
// Access: Public, Virtual
// Description: Applies whatever attributes are specified in the
// AccumulatedAttribs object (and by the attrib_types
// bitmask) to the vertices on this node, if
// appropriate. If this node uses geom arrays like a
// GeomNode, the supplied GeomTransformer may be used to
// unify shared arrays across multiple different nodes.
//
// This is a generalization of xform().
////////////////////////////////////////////////////////////////////
void GeomNode::
apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types,
GeomTransformer &transformer) {
if (pgraph_cat.is_debug()) {
pgraph_cat.debug()
<< "Transforming geometry.\n";
}
if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
if (!attribs._transform->is_identity()) {
transformer.transform_vertices(this, attribs._transform->get_mat());
}
}
if ((attrib_types & SceneGraphReducer::TT_color) != 0) {
if (attribs._color != (const RenderAttrib *)NULL) {
const ColorAttrib *ca = DCAST(ColorAttrib, attribs._color);
if (ca->get_color_type() == ColorAttrib::T_flat) {
transformer.set_color(this, ca->get_color());
}
}
}
if ((attrib_types & SceneGraphReducer::TT_color_scale) != 0) {
if (attribs._color_scale != (const RenderAttrib *)NULL) {
const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attribs._color_scale);
if (csa->get_scale() != LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f)) {
transformer.transform_colors(this, csa->get_scale());
}
}
}
if ((attrib_types & SceneGraphReducer::TT_tex_matrix) != 0) {
if (attribs._tex_matrix != (const RenderAttrib *)NULL) {
const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attribs._tex_matrix);
if (tma->get_mat() != LMatrix4f::ident_mat()) {
transformer.transform_texcoords(this, tma->get_mat());
}
}
}
if ((attrib_types & SceneGraphReducer::TT_other) != 0) {
if (!attribs._other->is_empty()) {
transformer.apply_state(this, attribs._other);
}
}
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: GeomNode::xform // Function: GeomNode::xform
// Access: Public, Virtual // Access: Public, Virtual
@ -200,6 +258,59 @@ combine_with(PandaNode *other) {
return PandaNode::combine_with(other); return PandaNode::combine_with(other);
} }
////////////////////////////////////////////////////////////////////
// Function: GeomNode::calc_tight_bounds
// Access: Public, Virtual
// Description: This is used to support
// NodePath::calc_tight_bounds(). It is not intended to
// be called directly, and it has nothing to do with the
// normal Panda bounding-volume computation.
//
// If the node contains any geometry, this updates
// min_point and max_point to enclose its bounding box.
// found_any is to be set true if the node has any
// geometry at all, or left alone if it has none. This
// method may be called over several nodes, so it may
// enter with min_point, max_point, and found_any
// already set.
////////////////////////////////////////////////////////////////////
CPT(TransformState) GeomNode::
calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any,
const TransformState *transform) const {
CPT(TransformState) next_transform =
PandaNode::calc_tight_bounds(min_point, max_point, found_any, transform);
const LMatrix4f &mat = next_transform->get_mat();
int num_geoms = get_num_geoms();
for (int i = 0; i < num_geoms; i++) {
Geom *geom = get_geom(i);
Geom::VertexIterator vi = geom->make_vertex_iterator();
int num_prims = geom->get_num_prims();
for (int p = 0; p < num_prims; p++) {
int length = geom->get_length(p);
for (int v = 0; v < length; v++) {
Vertexf vertex = geom->get_next_vertex(vi) * mat;
if (found_any) {
min_point.set(min(min_point[0], vertex[0]),
min(min_point[1], vertex[1]),
min(min_point[2], vertex[2]));
max_point.set(max(max_point[0], vertex[0]),
max(max_point[1], vertex[1]),
max(max_point[2], vertex[2]));
} else {
min_point = vertex;
max_point = vertex;
found_any = true;
}
}
}
}
return next_transform;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: GeomNode::add_geoms_from // Function: GeomNode::add_geoms_from
// Access: Published // Access: Published

View File

@ -44,8 +44,15 @@ protected:
public: public:
virtual ~GeomNode(); virtual ~GeomNode();
virtual PandaNode *make_copy() const; virtual PandaNode *make_copy() const;
virtual void apply_attribs_to_vertices(const AccumulatedAttribs &attribs,
int attrib_types,
GeomTransformer &transformer);
virtual void xform(const LMatrix4f &mat); virtual void xform(const LMatrix4f &mat);
virtual PandaNode *combine_with(PandaNode *other); virtual PandaNode *combine_with(PandaNode *other);
virtual CPT(TransformState)
calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
bool &found_any,
const TransformState *transform) const;
PUBLISHED: PUBLISHED:
INLINE int get_num_geoms() const; INLINE int get_num_geoms() const;

View File

@ -2788,7 +2788,7 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point) {
nassertr_always(!is_empty(), false); nassertr_always(!is_empty(), false);
bool found_any = false; bool found_any = false;
r_calc_tight_bounds(node(), min_point, max_point, found_any, node()->calc_tight_bounds(min_point, max_point, found_any,
TransformState::make_identity()); TransformState::make_identity());
return found_any; return found_any;
@ -3190,58 +3190,6 @@ r_force_recompute_bounds(PandaNode *node) {
} }
} }
////////////////////////////////////////////////////////////////////
// Function: NodePath::r_calc_tight_bounds
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
void NodePath::
r_calc_tight_bounds(PandaNode *node, LPoint3f &min_point, LPoint3f &max_point,
bool &found_any, const TransformState *transform) {
CPT(TransformState) next_transform =
transform->compose(node->get_transform());
if (node->is_geom_node()) {
GeomNode *gnode;
DCAST_INTO_V(gnode, node);
const LMatrix4f &mat = next_transform->get_mat();
int num_geoms = gnode->get_num_geoms();
for (int i = 0; i < num_geoms; i++) {
Geom *geom = gnode->get_geom(i);
Geom::VertexIterator vi = geom->make_vertex_iterator();
int num_prims = geom->get_num_prims();
for (int p = 0; p < num_prims; p++) {
int length = geom->get_length(p);
for (int v = 0; v < length; v++) {
Vertexf vertex = geom->get_next_vertex(vi) * mat;
if (found_any) {
min_point.set(min(min_point[0], vertex[0]),
min(min_point[1], vertex[1]),
min(min_point[2], vertex[2]));
max_point.set(max(max_point[0], vertex[0]),
max(max_point[1], vertex[1]),
max(max_point[2], vertex[2]));
} else {
min_point = vertex;
max_point = vertex;
found_any = true;
}
}
}
}
}
// Now consider children.
PandaNode::Children cr = node->get_children();
int num_children = cr.get_num_children();
for (int i = 0; i < num_children; i++) {
r_calc_tight_bounds(cr.get_child(i), min_point, max_point,
found_any, next_transform);
}
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: NodePath::r_find_texture // Function: NodePath::r_find_texture
// Access: Private // Access: Private

View File

@ -542,9 +542,6 @@ private:
void r_adjust_all_priorities(PandaNode *node, int adjustment); void r_adjust_all_priorities(PandaNode *node, int adjustment);
void r_force_recompute_bounds(PandaNode *node); void r_force_recompute_bounds(PandaNode *node);
void r_calc_tight_bounds(PandaNode *node,
LPoint3f &min_point, LPoint3f &max_point,
bool &found_any, const TransformState *transform);
typedef pset<Texture *> Textures; typedef pset<Texture *> Textures;
Texture *r_find_texture(PandaNode *node, const RenderState *state, Texture *r_find_texture(PandaNode *node, const RenderState *state,

View File

@ -23,6 +23,8 @@
#include "bamWriter.h" #include "bamWriter.h"
#include "indent.h" #include "indent.h"
#include "geometricBoundingVolume.h" #include "geometricBoundingVolume.h"
#include "sceneGraphReducer.h"
#include "accumulatedAttribs.h"
TypeHandle PandaNode::_type_handle; TypeHandle PandaNode::_type_handle;
@ -501,6 +503,18 @@ safe_to_combine() const {
return true; return true;
} }
////////////////////////////////////////////////////////////////////
// Function: PandaNode::safe_to_flatten_below
// Access: Public, Virtual
// Description: Returns true if a flatten operation may safely
// continue past this node, or false if it should drop
// all attributes here and stop.
////////////////////////////////////////////////////////////////////
bool PandaNode::
safe_to_flatten_below() const {
return true;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PandaNode::preserve_name // Function: PandaNode::preserve_name
// Access: Public, Virtual // Access: Public, Virtual
@ -513,6 +527,42 @@ preserve_name() const {
return false; return false;
} }
////////////////////////////////////////////////////////////////////
// Function: PandaNode::get_unsafe_to_apply_attribs
// Access: Public, Virtual
// Description: Returns the union of all attributes from
// SceneGraphReducer::AttribTypes that may not safely be
// applied to the vertices of this node. If this is
// nonzero, these attributes must be dropped at this
// node as a state change.
//
// This is a generalization of safe_to_transform().
////////////////////////////////////////////////////////////////////
int PandaNode::
get_unsafe_to_apply_attribs() const {
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::apply_attribs_to_vertices
// Access: Public, Virtual
// Description: Applies whatever attributes are specified in the
// AccumulatedAttribs object (and by the attrib_types
// bitmask) to the vertices on this node, if
// appropriate. If this node uses geom arrays like a
// GeomNode, the supplied GeomTransformer may be used to
// unify shared arrays across multiple different nodes.
//
// This is a generalization of xform().
////////////////////////////////////////////////////////////////////
void PandaNode::
apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types,
GeomTransformer &transformer) {
if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
xform(attribs._transform->get_mat());
}
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PandaNode::xform // Function: PandaNode::xform
// Access: Public, Virtual // Access: Public, Virtual
@ -568,6 +618,41 @@ combine_with(PandaNode *other) {
return (PandaNode *)NULL; return (PandaNode *)NULL;
} }
////////////////////////////////////////////////////////////////////
// Function: PandaNode::calc_tight_bounds
// Access: Public, Virtual
// Description: This is used to support
// NodePath::calc_tight_bounds(). It is not intended to
// be called directly, and it has nothing to do with the
// normal Panda bounding-volume computation.
//
// If the node contains any geometry, this updates
// min_point and max_point to enclose its bounding box.
// found_any is to be set true if the node has any
// geometry at all, or left alone if it has none. This
// method may be called over several nodes, so it may
// enter with min_point, max_point, and found_any
// already set.
//
// This function is recursive, and the return value is
// the transform after it has been modified by this
// node's transform.
////////////////////////////////////////////////////////////////////
CPT(TransformState) PandaNode::
calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any,
const TransformState *transform) const {
CPT(TransformState) next_transform = transform->compose(get_transform());
Children cr = get_children();
int num_children = cr.get_num_children();
for (int i = 0; i < num_children; i++) {
cr.get_child(i)->calc_tight_bounds(min_point, max_point,
found_any, next_transform);
}
return next_transform;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PandaNode::has_cull_callback // Function: PandaNode::has_cull_callback
// Access: Public, Virtual // Access: Public, Virtual

View File

@ -45,6 +45,8 @@ class CullTraverser;
class CullTraverserData; class CullTraverserData;
class Light; class Light;
class FactoryParams; class FactoryParams;
class AccumulatedAttribs;
class GeomTransformer;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Class : PandaNode // Class : PandaNode
@ -71,9 +73,18 @@ public:
virtual bool safe_to_transform() const; virtual bool safe_to_transform() const;
virtual bool safe_to_modify_transform() const; virtual bool safe_to_modify_transform() const;
virtual bool safe_to_combine() const; virtual bool safe_to_combine() const;
virtual bool safe_to_flatten_below() const;
virtual bool preserve_name() const; virtual bool preserve_name() const;
virtual int get_unsafe_to_apply_attribs() const;
virtual void apply_attribs_to_vertices(const AccumulatedAttribs &attribs,
int attrib_types,
GeomTransformer &transformer);
virtual void xform(const LMatrix4f &mat); virtual void xform(const LMatrix4f &mat);
virtual PandaNode *combine_with(PandaNode *other); virtual PandaNode *combine_with(PandaNode *other);
virtual CPT(TransformState)
calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
bool &found_any,
const TransformState *transform) const;
virtual bool has_cull_callback() const; virtual bool has_cull_callback() const;
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data); virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data);

View File

@ -1,3 +1,4 @@
#include "accumulatedAttribs.cxx"
#include "ambientLight.cxx" #include "ambientLight.cxx"
#include "bamFile.cxx" #include "bamFile.cxx"
#include "billboardEffect.cxx" #include "billboardEffect.cxx"

View File

@ -18,39 +18,58 @@
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::AccumulatedAttribs::Constructor // Function: SceneGraphReducer::Constructor
// Access: Public // Access: Published
// Description: // Description:
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE SceneGraphReducer::AccumulatedAttribs:: INLINE SceneGraphReducer::
AccumulatedAttribs() { SceneGraphReducer() {
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::AccumulatedAttribs::Copy Constructor // Function: SceneGraphReducer::Destructor
// Access: Public // Access: Published
// Description: // Description:
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE SceneGraphReducer::AccumulatedAttribs:: INLINE SceneGraphReducer::
AccumulatedAttribs(const SceneGraphReducer::AccumulatedAttribs &copy) : ~SceneGraphReducer() {
_transform(copy._transform), }
_color(copy._color),
_color_scale(copy._color_scale),
_tex_matrix(copy._tex_matrix), ////////////////////////////////////////////////////////////////////
_other(copy._other) // Function: SceneGraphReducer::apply_attribs
{ // Access: Published
// Description: Walks the scene graph, accumulating attribs of
// the indicated types, applying them to the vertices,
// and removing them from the scene graph. This has a
// performance optimization benefit in itself, but is
// especially useful to pave the way for a call to
// flatten() and greatly improve the effectiveness of
// the flattening operation.
//
// Multiply instanced geometry is duplicated before the
// attribs are applied.
//
// Of course, this operation does make certain dynamic
// operations impossible.
////////////////////////////////////////////////////////////////////
INLINE void SceneGraphReducer::
apply_attribs(PandaNode *node, int attrib_types) {
AccumulatedAttribs attribs;
r_apply_attribs(node, attribs, attrib_types, _transformer);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::AccumulatedAttribs::Copy Assignment // Function: SceneGraphReducer::apply_attribs
// Access: Public // Access: Published
// Description: // Description: This flavor of apply_attribs() can be called
// recursively from within another flatten process
// (e.g. from PandaNode::apply_attribs_to_vertices()).
// The parameters were presumably received from a parent
// SceneGraphReducer object.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE void SceneGraphReducer::AccumulatedAttribs:: INLINE void SceneGraphReducer::
operator = (const SceneGraphReducer::AccumulatedAttribs &copy) { apply_attribs(PandaNode *node, const AccumulatedAttribs &attribs,
_transform = copy._transform; int attrib_types, GeomTransformer &transformer) {
_color = copy._color; r_apply_attribs(node, attribs, attrib_types, transformer);
_color_scale = copy._color_scale;
_tex_matrix = copy._tex_matrix;
_other = copy._other;
} }

View File

@ -21,6 +21,7 @@
#include "colorAttrib.h" #include "colorAttrib.h"
#include "texMatrixAttrib.h" #include "texMatrixAttrib.h"
#include "colorScaleAttrib.h" #include "colorScaleAttrib.h"
#include "accumulatedAttribs.h"
#include "geomNode.h" #include "geomNode.h"
#include "pointerTo.h" #include "pointerTo.h"
@ -28,292 +29,15 @@
#include "indent.h" #include "indent.h"
#include "plist.h" #include "plist.h"
////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::AccumulatedAttribs::write
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void SceneGraphReducer::AccumulatedAttribs::
write(ostream &out, int attrib_types, int indent_level) const {
if ((attrib_types & TT_transform) != 0) {
_transform->write(out, indent_level);
}
if ((attrib_types & TT_color) != 0) {
if (_color == (const RenderAttrib *)NULL) {
indent(out, indent_level) << "no color\n";
} else {
_color->write(out, indent_level);
}
}
if ((attrib_types & TT_color_scale) != 0) {
if (_color_scale == (const RenderAttrib *)NULL) {
indent(out, indent_level) << "no color scale\n";
} else {
_color_scale->write(out, indent_level);
}
}
if ((attrib_types & TT_tex_matrix) != 0) {
if (_tex_matrix == (const RenderAttrib *)NULL) {
indent(out, indent_level) << "no tex matrix\n";
} else {
_tex_matrix->write(out, indent_level);
}
}
if ((attrib_types & TT_other) != 0) {
_other->write(out, indent_level);
}
}
////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::AccumulatedAttribs::collect
// Access: Public
// Description: Collects the state and transform from the indicated
// node and adds it to the accumulator, removing it from
// the node.
////////////////////////////////////////////////////////////////////
void SceneGraphReducer::AccumulatedAttribs::
collect(PandaNode *node, int attrib_types) {
if ((attrib_types & TT_transform) != 0) {
// Collect the node's transform.
nassertv(_transform != (TransformState *)NULL);
_transform = _transform->compose(node->get_transform());
node->set_transform(TransformState::make_identity());
}
if ((attrib_types & TT_color) != 0) {
const RenderAttrib *node_attrib =
node->get_attrib(ColorAttrib::get_class_type());
if (node_attrib != (const RenderAttrib *)NULL) {
// The node has a color attribute; apply it.
if (_color == (const RenderAttrib *)NULL) {
_color = node_attrib;
} else {
_color = _color->compose(node_attrib);
}
node->clear_attrib(ColorAttrib::get_class_type());
}
}
if ((attrib_types & TT_color_scale) != 0) {
const RenderAttrib *node_attrib =
node->get_attrib(ColorScaleAttrib::get_class_type());
if (node_attrib != (const RenderAttrib *)NULL) {
// The node has a color scale attribute; apply it.
if (_color_scale == (const RenderAttrib *)NULL) {
_color_scale = node_attrib;
} else {
_color_scale = _color_scale->compose(node_attrib);
}
node->clear_attrib(ColorScaleAttrib::get_class_type());
}
}
if ((attrib_types & TT_tex_matrix) != 0) {
const RenderAttrib *node_attrib =
node->get_attrib(TexMatrixAttrib::get_class_type());
if (node_attrib != (const RenderAttrib *)NULL) {
// The node has a tex matrix attribute; apply it.
if (_tex_matrix == (const RenderAttrib *)NULL) {
_tex_matrix = node_attrib;
} else {
_tex_matrix = _tex_matrix->compose(node_attrib);
}
node->clear_attrib(TexMatrixAttrib::get_class_type());
}
}
if ((attrib_types & TT_transform) != 0) {
// Collect everything else.
nassertv(_other != (RenderState *)NULL);
_other = _other->compose(node->get_state());
node->set_state(RenderState::make_empty());
}
}
////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::AccumulatedAttribs::apply_to_node
// Access: Public
// Description: Stores the indicated attributes in the node's
// transform and state information; does not attempt to
// apply the properties to the vertices. Clears the
// attributes from the accumulator for future
// traversals.
////////////////////////////////////////////////////////////////////
void SceneGraphReducer::AccumulatedAttribs::
apply_to_node(PandaNode *node, int attrib_types) {
if ((attrib_types & TT_transform) != 0) {
node->set_transform(_transform->compose(node->get_transform()));
_transform = TransformState::make_identity();
}
if ((attrib_types & TT_color) != 0) {
if (_color != (RenderAttrib *)NULL) {
const RenderAttrib *node_attrib =
node->get_attrib(ColorAttrib::get_class_type());
if (node_attrib != (RenderAttrib *)NULL) {
node->set_attrib(_color->compose(node_attrib));
} else {
node->set_attrib(_color);
}
_color = (RenderAttrib *)NULL;
}
}
if ((attrib_types & TT_color_scale) != 0) {
if (_color_scale != (RenderAttrib *)NULL) {
const RenderAttrib *node_attrib =
node->get_attrib(ColorScaleAttrib::get_class_type());
if (node_attrib != (RenderAttrib *)NULL) {
node->set_attrib(_color_scale->compose(node_attrib));
} else {
node->set_attrib(_color_scale);
}
_color_scale = (RenderAttrib *)NULL;
}
}
if ((attrib_types & TT_tex_matrix) != 0) {
if (_tex_matrix != (RenderAttrib *)NULL) {
const RenderAttrib *node_attrib =
node->get_attrib(TexMatrixAttrib::get_class_type());
if (node_attrib != (RenderAttrib *)NULL) {
node->set_attrib(_tex_matrix->compose(node_attrib));
} else {
node->set_attrib(_tex_matrix);
}
_tex_matrix = (RenderAttrib *)NULL;
}
}
if ((attrib_types & TT_other) != 0) {
node->set_state(_other->compose(node->get_state()));
_other = RenderState::make_empty();
}
}
////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::AccumulatedAttribs::apply_to_vertices
// Access: Public
// Description: Applies the indicated attributes to the node so that
// they do not need to be stored as separate attributes
// any more.
////////////////////////////////////////////////////////////////////
void SceneGraphReducer::AccumulatedAttribs::
apply_to_vertices(PandaNode *node, int attrib_types,
GeomTransformer &transformer) {
if (node->is_geom_node()) {
if (pgraph_cat.is_debug()) {
pgraph_cat.debug()
<< "Transforming geometry.\n";
}
// We treat GeomNodes as a special case, since we can apply more
// than just a transform matrix and so we can share vertex arrays
// across different GeomNodes.
GeomNode *gnode = DCAST(GeomNode, node);
if ((attrib_types & TT_transform) != 0) {
if (!_transform->is_identity()) {
transformer.transform_vertices(gnode, _transform->get_mat());
}
}
if ((attrib_types & TT_color) != 0) {
if (_color != (const RenderAttrib *)NULL) {
const ColorAttrib *ca = DCAST(ColorAttrib, _color);
if (ca->get_color_type() == ColorAttrib::T_flat) {
transformer.set_color(gnode, ca->get_color());
}
}
}
if ((attrib_types & TT_color_scale) != 0) {
if (_color_scale != (const RenderAttrib *)NULL) {
const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, _color_scale);
if (csa->get_scale() != LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f)) {
transformer.transform_colors(gnode, csa->get_scale());
}
}
}
if ((attrib_types & TT_tex_matrix) != 0) {
if (_tex_matrix != (const RenderAttrib *)NULL) {
const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, _tex_matrix);
if (tma->get_mat() != LMatrix4f::ident_mat()) {
transformer.transform_texcoords(gnode, tma->get_mat());
}
}
}
if ((attrib_types & TT_other) != 0) {
if (!_other->is_empty()) {
transformer.apply_state(gnode, _other);
}
}
} else {
// This handles any kind of node other than a GeomNode.
if ((attrib_types & TT_transform) != 0) {
node->xform(_transform->get_mat());
}
}
}
////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
SceneGraphReducer::
SceneGraphReducer() {
}
////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
SceneGraphReducer::
~SceneGraphReducer() {
}
////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::apply_attribs
// Access: Public
// Description: Walks the scene graph, accumulating attribs of
// the indicated types, applying them to the vertices,
// and removing them from the scene graph. This has a
// performance optimization benefit in itself, but is
// especially useful to pave the way for a call to
// flatten() and greatly improve the effectiveness of
// the flattening operation.
//
// Multiply instanced geometry is duplicated before the
// attribs are applied.
//
// Of course, this operation does make certain dynamic
// operations impossible.
////////////////////////////////////////////////////////////////////
void SceneGraphReducer::
apply_attribs(PandaNode *node, int attrib_types) {
AccumulatedAttribs trans;
trans._transform = TransformState::make_identity();
trans._color = (ColorAttrib *)NULL;
trans._color_scale = (ColorScaleAttrib *)NULL;
trans._tex_matrix = (TexMatrixAttrib *)NULL;
trans._other = RenderState::make_empty();
r_apply_attribs(node, attrib_types, trans);
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::flatten // Function: SceneGraphReducer::flatten
// Access: Public // Access: Published
// Description: Simplifies the graph by removing unnecessary nodes // Description: Simplifies the graph by removing unnecessary nodes
// and nodes. // and nodes.
// //
// In general, a node (and its parent node) is a // In general, a node (and its parent node) is a
// candidate for removal if the node has no siblings and // candidate for removal if the node has no siblings and
// the node and node have no special properties. The // the node has no special properties.
// definition of what, precisely, is a 'special
// property' may be extended by subclassing from this
// type and redefining consider_node() appropriately.
// //
// If combine_siblings is true, sibling nodes may also // If combine_siblings is true, sibling nodes may also
// be collapsed into a single node. This will further // be collapsed into a single node. This will further
@ -365,8 +89,8 @@ flatten(PandaNode *root, bool combine_siblings) {
// Description: The recursive implementation of apply_attribs(). // Description: The recursive implementation of apply_attribs().
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void SceneGraphReducer:: void SceneGraphReducer::
r_apply_attribs(PandaNode *node, int attrib_types, r_apply_attribs(PandaNode *node, const AccumulatedAttribs &attribs,
SceneGraphReducer::AccumulatedAttribs trans) { int attrib_types, GeomTransformer &transformer) {
if (pgraph_cat.is_debug()) { if (pgraph_cat.is_debug()) {
pgraph_cat.debug() pgraph_cat.debug()
<< "r_apply_attribs(" << *node << "), node's attribs are:\n"; << "r_apply_attribs(" << *node << "), node's attribs are:\n";
@ -375,13 +99,14 @@ r_apply_attribs(PandaNode *node, int attrib_types,
node->get_effects()->write(pgraph_cat.debug(false), 2); node->get_effects()->write(pgraph_cat.debug(false), 2);
} }
trans.collect(node, attrib_types); AccumulatedAttribs next_attribs(attribs);
next_attribs.collect(node, attrib_types);
if (pgraph_cat.is_debug()) { if (pgraph_cat.is_debug()) {
pgraph_cat.debug() pgraph_cat.debug()
<< "Got attribs from " << *node << "\n" << "Got attribs from " << *node << "\n"
<< "Accumulated attribs are:\n"; << "Accumulated attribs are:\n";
trans.write(pgraph_cat.debug(false), attrib_types, 2); next_attribs.write(pgraph_cat.debug(false), attrib_types, 2);
} }
// Check to see if we can't propagate any of these attribs past // Check to see if we can't propagate any of these attribs past
@ -405,6 +130,7 @@ r_apply_attribs(PandaNode *node, int attrib_types,
} }
apply_types |= TT_transform; apply_types |= TT_transform;
} }
apply_types |= node->get_unsafe_to_apply_attribs();
// Also, check the children of this node. If any of them indicates // Also, check the children of this node. If any of them indicates
// it is not safe to modify its transform, we must drop our // it is not safe to modify its transform, we must drop our
@ -429,10 +155,10 @@ r_apply_attribs(PandaNode *node, int attrib_types,
} }
// Directly store whatever attributes we must, // Directly store whatever attributes we must,
trans.apply_to_node(node, attrib_types & apply_types); next_attribs.apply_to_node(node, attrib_types & apply_types);
// And apply the rest to the vertices. // And apply the rest to the vertices.
trans.apply_to_vertices(node, attrib_types, _transformer); node->apply_attribs_to_vertices(next_attribs, attrib_types, transformer);
// Do we need to copy any children to flatten instances? // Do we need to copy any children to flatten instances?
bool resist_copy = false; bool resist_copy = false;
@ -473,14 +199,14 @@ r_apply_attribs(PandaNode *node, int attrib_types,
if (resist_copy) { if (resist_copy) {
// If any of our children should have been copied but weren't, we // If any of our children should have been copied but weren't, we
// need to drop the state here before continuing. // need to drop the state here before continuing.
trans.apply_to_node(node, attrib_types); next_attribs.apply_to_node(node, attrib_types);
} }
// Now it's safe to traverse through all of our children. // Now it's safe to traverse through all of our children.
nassertv(num_children == node->get_num_children()); nassertv(num_children == node->get_num_children());
for (i = 0; i < num_children; i++) { for (i = 0; i < num_children; i++) {
PandaNode *child_node = node->get_child(i); PandaNode *child_node = node->get_child(i);
r_apply_attribs(child_node, attrib_types, trans); r_apply_attribs(child_node, next_attribs, attrib_types, transformer);
} }
} }
@ -637,12 +363,10 @@ flatten_siblings(PandaNode *parent_node) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::consider_child // Function: SceneGraphReducer::consider_child
// Access: Protected, Virtual // Access: Protected
// Description: Decides whether or not the indicated child node is a // Description: Decides whether or not the indicated child node is a
// suitable candidate for removal. Returns true if the // suitable candidate for removal. Returns true if the
// node may be removed, false if it should be kept. This // node may be removed, false if it should be kept.
// function may be extended in a user class to protect
// special kinds of nodes from deletion.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool SceneGraphReducer:: bool SceneGraphReducer::
consider_child(PandaNode *grandparent_node, PandaNode *parent_node, consider_child(PandaNode *grandparent_node, PandaNode *parent_node,
@ -671,7 +395,7 @@ consider_child(PandaNode *grandparent_node, PandaNode *parent_node,
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer:c:onsider_siblings // Function: SceneGraphReducer:c:onsider_siblings
// Access: Protected, Virtual // Access: Protected
// Description: Decides whether or not the indicated sibling nodes // Description: Decides whether or not the indicated sibling nodes
// should be collapsed into a single node or not. // should be collapsed into a single node or not.
// Returns true if the nodes may be collapsed, false if // Returns true if the nodes may be collapsed, false if
@ -688,14 +412,11 @@ consider_siblings(PandaNode *parent_node, PandaNode *child1,
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::do_flatten_child // Function: SceneGraphReducer::do_flatten_child
// Access: Protected, Virtual // Access: Protected
// Description: Collapses together the indicated parent node and // Description: Collapses together the indicated parent node and
// child node and leaves the result attached to the // child node and leaves the result attached to the
// grandparent. The return value is true if the node is // grandparent. The return value is true if the node is
// successfully collapsed, false if we chickened out. // successfully collapsed, false if we chickened out.
//
// This function may be extended in a user class to
// handle special kinds of nodes.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool SceneGraphReducer:: bool SceneGraphReducer::
do_flatten_child(PandaNode *grandparent_node, PandaNode *parent_node, do_flatten_child(PandaNode *grandparent_node, PandaNode *parent_node,
@ -730,7 +451,7 @@ do_flatten_child(PandaNode *grandparent_node, PandaNode *parent_node,
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::do_flatten_siblings // Function: SceneGraphReducer::do_flatten_siblings
// Access: Protected, Virtual // Access: Protected
// Description: Performs the work of collapsing two sibling nodes // Description: Performs the work of collapsing two sibling nodes
// together into a single node, leaving the resulting // together into a single node, leaving the resulting
// node attached to the parent. // node attached to the parent.
@ -779,7 +500,7 @@ do_flatten_siblings(PandaNode *parent_node, PandaNode *child1,
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::collapse_nodes // Function: SceneGraphReducer::collapse_nodes
// Access: Protected, Virtual // Access: Protected
// Description: Collapses the two nodes into a single node, if // Description: Collapses the two nodes into a single node, if
// possible. The 'siblings' flag is true if the two // possible. The 'siblings' flag is true if the two
// nodes are siblings nodes; otherwise, node1 is a // nodes are siblings nodes; otherwise, node1 is a
@ -787,9 +508,6 @@ do_flatten_siblings(PandaNode *parent_node, PandaNode *child1,
// node, which may be either one of the source nodes, or // node, which may be either one of the source nodes, or
// a new node altogether, or it may be NULL to indicate // a new node altogether, or it may be NULL to indicate
// that the collapse operation could not take place. // that the collapse operation could not take place.
//
// This function may be extended in a user class to
// handle combining special kinds of nodes.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
PT(PandaNode) SceneGraphReducer:: PT(PandaNode) SceneGraphReducer::
collapse_nodes(PandaNode *node1, PandaNode *node2, bool siblings) { collapse_nodes(PandaNode *node1, PandaNode *node2, bool siblings) {
@ -799,7 +517,7 @@ collapse_nodes(PandaNode *node1, PandaNode *node2, bool siblings) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::choose_name // Function: SceneGraphReducer::choose_name
// Access: Protected, Virtual // Access: Protected
// Description: Chooses a suitable name for the collapsed node, based // Description: Chooses a suitable name for the collapsed node, based
// on the names of the two sources nodes. // on the names of the two sources nodes.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -23,11 +23,14 @@
#include "transformState.h" #include "transformState.h"
#include "renderAttrib.h" #include "renderAttrib.h"
#include "renderState.h" #include "renderState.h"
#include "accumulatedAttribs.h"
#include "geomTransformer.h" #include "geomTransformer.h"
#include "typedObject.h" #include "typedObject.h"
#include "pointerTo.h" #include "pointerTo.h"
class PandaNode;
/////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////
// Class : SceneGraphReducer // Class : SceneGraphReducer
// Description : An interface for simplifying ("flattening") scene // Description : An interface for simplifying ("flattening") scene
@ -41,8 +44,8 @@
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
class EXPCL_PANDA SceneGraphReducer { class EXPCL_PANDA SceneGraphReducer {
PUBLISHED: PUBLISHED:
SceneGraphReducer(); INLINE SceneGraphReducer();
virtual ~SceneGraphReducer(); INLINE ~SceneGraphReducer();
enum AttribTypes { enum AttribTypes {
TT_transform = 0x001, TT_transform = 0x001,
@ -52,52 +55,34 @@ PUBLISHED:
TT_other = 0x010, TT_other = 0x010,
}; };
void apply_attribs(PandaNode *node, int attrib_types = ~0); INLINE void apply_attribs(PandaNode *node, int attrib_types = ~0);
INLINE void apply_attribs(PandaNode *node, const AccumulatedAttribs &attribs,
int attrib_types, GeomTransformer &transformer);
int flatten(PandaNode *root, bool combine_siblings); int flatten(PandaNode *root, bool combine_siblings);
protected: protected:
class AccumulatedAttribs { void r_apply_attribs(PandaNode *node, const AccumulatedAttribs &attribs,
public: int attrib_types, GeomTransformer &transformer);
INLINE AccumulatedAttribs();
INLINE AccumulatedAttribs(const AccumulatedAttribs &copy);
INLINE void operator = (const AccumulatedAttribs &copy);
void write(ostream &out, int attrib_types, int indent_level) const;
void collect(PandaNode *node, int attrib_types);
void apply_to_node(PandaNode *node, int attrib_types);
void apply_to_vertices(PandaNode *node, int attrib_types,
GeomTransformer &transfomer);
CPT(TransformState) _transform;
CPT(RenderAttrib) _color;
CPT(RenderAttrib) _color_scale;
CPT(RenderAttrib) _tex_matrix;
CPT(RenderState) _other;
};
void r_apply_attribs(PandaNode *node, int attrib_types,
AccumulatedAttribs trans);
int r_flatten(PandaNode *grandparent_node, PandaNode *parent_node, int r_flatten(PandaNode *grandparent_node, PandaNode *parent_node,
bool combine_siblings); bool combine_siblings);
int flatten_siblings(PandaNode *parent_node); int flatten_siblings(PandaNode *parent_node);
virtual bool consider_child(PandaNode *grandparent_node, bool consider_child(PandaNode *grandparent_node,
PandaNode *parent_node, PandaNode *child_node); PandaNode *parent_node, PandaNode *child_node);
virtual bool consider_siblings(PandaNode *parent_node, PandaNode *child1, bool consider_siblings(PandaNode *parent_node, PandaNode *child1,
PandaNode *child2); PandaNode *child2);
virtual bool do_flatten_child(PandaNode *grandparent_node, bool do_flatten_child(PandaNode *grandparent_node,
PandaNode *parent_node, PandaNode *child_node); PandaNode *parent_node, PandaNode *child_node);
virtual PandaNode *do_flatten_siblings(PandaNode *parent_node, PandaNode *do_flatten_siblings(PandaNode *parent_node,
PandaNode *child1, PandaNode *child2); PandaNode *child1, PandaNode *child2);
virtual PT(PandaNode) collapse_nodes(PandaNode *node1, PandaNode *node2, PT(PandaNode) collapse_nodes(PandaNode *node1, PandaNode *node2,
bool siblings); bool siblings);
virtual void choose_name(PandaNode *preserve, PandaNode *source1, void choose_name(PandaNode *preserve, PandaNode *source1,
PandaNode *source2); PandaNode *source2);
private: private:

View File

@ -779,7 +779,6 @@ TextNode *PGItem::
get_text_node() { get_text_node() {
if (_text_node == (TextNode *)NULL) { if (_text_node == (TextNode *)NULL) {
_text_node = new TextNode("pguiText"); _text_node = new TextNode("pguiText");
_text_node->freeze();
_text_node->set_text_color(0.0f, 0.0f, 0.0f, 1.0f); _text_node->set_text_color(0.0f, 0.0f, 0.0f, 1.0f);
// The default TextNode is aligned to the left, for the // The default TextNode is aligned to the left, for the

View File

@ -20,70 +20,25 @@
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::freeze // Function: TextNode::freeze
// Access: Published // Access: Published
// Description: Freezes the TextNode in its current state, so that // Description: This method is deprecated and no longer does
// updates will not immediately be displayed. A series // anything. It is included for historical purposes
// of state changes may then be applied in succession, // only and will shortly be removed.
// which will not force the TextNode to be recomputed.
// When thaw() is later called, the TextNode will update
// itself exactly once to reflect all the state changes
// that were made.
//
// freeze() and thaw() can nest. Strictly speaking,
// each call to freeze() increments the current freeze
// level, while each call to thaw() decrements it. The
// TextNode will only be updated when the current freeze
// level is zero.
//
// The return value of freeze() is the freeze level
// *before* the freeze took place. This number should
// match the return value of the matching thaw().
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE int TextNode:: INLINE int TextNode::
freeze() { freeze() {
if (text_cat.is_debug()) { return 0;
text_cat.debug()
<< "Freezing " << this->get_name() << ", level = "
<< _freeze_level << "\n";
}
return _freeze_level++;
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::get_freeze_level
// Access: Published
// Description: Returns the current freeze level. The TextNode will
// not be updated visually unless this number is zero.
// See freeze().
////////////////////////////////////////////////////////////////////
INLINE int TextNode::
get_freeze_level() const {
return _freeze_level;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::thaw // Function: TextNode::thaw
// Access: Published // Access: Published
// Description: Allows changes made since the last freeze() to be // Description: This method is deprecated and no longer does
// visible. Strictly speaking, this actually decrements // anything. It is included for historical purposes
// the freeze level, and updates the TextNode if the // only and will shortly be removed.
// level reaches zero. The return value is the new
// freeze level after adjusting. See freeze().
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE int TextNode:: INLINE int TextNode::
thaw() { thaw() {
if (text_cat.is_debug()) { return 0;
text_cat.debug()
<< "Thawing " << this->get_name() << ", level = "
<< _freeze_level-1 << "\n";
}
nassertr(_freeze_level > 0, _freeze_level);
_freeze_level--;
if (_freeze_level == 0 && _needs_rebuild) {
do_rebuild();
}
return _freeze_level;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -95,7 +50,7 @@ INLINE void TextNode::
set_font(TextFont *font) { set_font(TextFont *font) {
if (_font != font) { if (_font != font) {
_font = font; _font = font;
rebuild(true); invalidate_with_measure();
} }
} }
@ -193,7 +148,7 @@ INLINE void TextNode::
set_slant(float slant) { set_slant(float slant) {
if (_slant != slant) { if (_slant != slant) {
_slant = slant; _slant = slant;
rebuild(true); invalidate_with_measure();
} }
} }
@ -216,7 +171,7 @@ INLINE void TextNode::
set_align(TextNode::Alignment align_type) { set_align(TextNode::Alignment align_type) {
if (_align != align_type) { if (_align != align_type) {
_align = align_type; _align = align_type;
rebuild(true); invalidate_with_measure();
} }
} }
@ -241,7 +196,7 @@ set_wordwrap(float wordwrap) {
if (!has_wordwrap() || _wordwrap_width != wordwrap) { if (!has_wordwrap() || _wordwrap_width != wordwrap) {
_flags |= F_has_wordwrap; _flags |= F_has_wordwrap;
_wordwrap_width = wordwrap; _wordwrap_width = wordwrap;
rebuild(true); invalidate_with_measure();
} }
} }
@ -255,7 +210,7 @@ INLINE void TextNode::
clear_wordwrap() { clear_wordwrap() {
if (has_wordwrap()) { if (has_wordwrap()) {
_flags &= ~F_has_wordwrap; _flags &= ~F_has_wordwrap;
rebuild(true); invalidate_with_measure();
} }
} }
@ -299,7 +254,7 @@ set_text_color(const Colorf &text_color) {
if (!has_text_color() || _text_color != text_color) { if (!has_text_color() || _text_color != text_color) {
_text_color = text_color; _text_color = text_color;
_flags |= F_has_text_color; _flags |= F_has_text_color;
rebuild(false); invalidate_no_measure();
} }
} }
@ -313,7 +268,7 @@ INLINE void TextNode::
clear_text_color() { clear_text_color() {
if (has_text_color()) { if (has_text_color()) {
_flags &= ~F_has_text_color; _flags &= ~F_has_text_color;
rebuild(false); invalidate_no_measure();
} }
} }
@ -356,7 +311,7 @@ INLINE void TextNode::
set_frame_color(const Colorf &frame_color) { set_frame_color(const Colorf &frame_color) {
if (_frame_color != frame_color) { if (_frame_color != frame_color) {
_frame_color = frame_color; _frame_color = frame_color;
rebuild(false); invalidate_no_measure();
} }
} }
@ -381,7 +336,7 @@ set_card_border(float size, float uv_portion) {
_flags |= F_has_card_border; _flags |= F_has_card_border;
_card_border_size = size; _card_border_size = size;
_card_border_uv_portion = uv_portion; _card_border_uv_portion = uv_portion;
rebuild(false); invalidate_no_measure();
} }
} }
@ -394,7 +349,7 @@ INLINE void TextNode::
clear_card_border() { clear_card_border() {
if (has_card_border()) { if (has_card_border()) {
_flags &= ~F_has_card_border; _flags &= ~F_has_card_border;
rebuild(false); invalidate_no_measure();
} }
} }
@ -447,7 +402,7 @@ INLINE void TextNode::
set_card_color(const Colorf &card_color) { set_card_color(const Colorf &card_color) {
if (_card_color != card_color) { if (_card_color != card_color) {
_card_color = card_color; _card_color = card_color;
rebuild(false); invalidate_no_measure();
} }
} }
@ -474,7 +429,7 @@ set_card_texture(Texture *card_texture) {
if (!has_card_texture() || _card_texture != card_texture) { if (!has_card_texture() || _card_texture != card_texture) {
_flags |= F_has_card_texture; _flags |= F_has_card_texture;
_card_texture = card_texture; _card_texture = card_texture;
rebuild(false); invalidate_no_measure();
} }
} }
} }
@ -489,7 +444,7 @@ clear_card_texture() {
if (has_card_texture()) { if (has_card_texture()) {
_flags &= ~F_has_card_texture; _flags &= ~F_has_card_texture;
_card_texture = NULL; _card_texture = NULL;
rebuild(false); invalidate_no_measure();
} }
} }
@ -532,7 +487,7 @@ INLINE void TextNode::
set_shadow_color(const Colorf &shadow_color) { set_shadow_color(const Colorf &shadow_color) {
if (_shadow_color != shadow_color) { if (_shadow_color != shadow_color) {
_shadow_color = shadow_color; _shadow_color = shadow_color;
rebuild(false); invalidate_no_measure();
} }
} }
@ -560,7 +515,7 @@ set_frame_as_margin(float left, float right, float bottom, float top) {
_flags |= (F_has_frame | F_frame_as_margin); _flags |= (F_has_frame | F_frame_as_margin);
_frame_ul.set(left, top); _frame_ul.set(left, top);
_frame_lr.set(right, bottom); _frame_lr.set(right, bottom);
rebuild(false); invalidate_no_measure();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -579,7 +534,7 @@ set_frame_actual(float left, float right, float bottom, float top) {
_flags &= ~F_frame_as_margin; _flags &= ~F_frame_as_margin;
_frame_ul.set(left, top); _frame_ul.set(left, top);
_frame_lr.set(right, bottom); _frame_lr.set(right, bottom);
rebuild(false); invalidate_no_measure();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -591,7 +546,7 @@ set_frame_actual(float left, float right, float bottom, float top) {
INLINE void TextNode:: INLINE void TextNode::
clear_frame() { clear_frame() {
_flags &= ~F_has_frame; _flags &= ~F_has_frame;
rebuild(false); invalidate_no_measure();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -650,10 +605,11 @@ INLINE LVecBase4f TextNode::
get_frame_actual() const { get_frame_actual() const {
nassertr(has_frame(), LVecBase4f(0.0, 0.0, 0.0, 0.0)); nassertr(has_frame(), LVecBase4f(0.0, 0.0, 0.0, 0.0));
if (is_frame_as_margin()) { if (is_frame_as_margin()) {
return LVecBase4f(get_left() - _frame_ul[0], check_measure();
get_right() + _frame_lr[0], return LVecBase4f(_ul2d[0] - _frame_ul[0],
get_bottom() - _frame_lr[1], _lr2d[0] + _frame_lr[0],
get_top() + _frame_ul[1]); _lr2d[1] - _frame_lr[1],
_ul2d[1] + _frame_ul[1]);
} else { } else {
return get_frame_as_set(); return get_frame_as_set();
} }
@ -723,7 +679,7 @@ set_card_as_margin(float left, float right, float bottom, float top) {
_flags |= (F_has_card | F_card_as_margin); _flags |= (F_has_card | F_card_as_margin);
_card_ul.set(left, top); _card_ul.set(left, top);
_card_lr.set(right, bottom); _card_lr.set(right, bottom);
rebuild(false); invalidate_no_measure();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -742,7 +698,7 @@ set_card_actual(float left, float right, float bottom, float top) {
_flags &= ~F_card_as_margin; _flags &= ~F_card_as_margin;
_card_ul.set(left, top); _card_ul.set(left, top);
_card_lr.set(right, bottom); _card_lr.set(right, bottom);
rebuild(false); invalidate_no_measure();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -754,7 +710,7 @@ set_card_actual(float left, float right, float bottom, float top) {
INLINE void TextNode:: INLINE void TextNode::
clear_card() { clear_card() {
_flags &= ~F_has_card; _flags &= ~F_has_card;
rebuild(false); invalidate_no_measure();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -816,13 +772,15 @@ get_card_as_set() const {
INLINE LVecBase4f TextNode:: INLINE LVecBase4f TextNode::
get_card_actual() const { get_card_actual() const {
if (!has_card()) { if (!has_card()) {
return LVecBase4f(get_left(), get_right(), get_bottom(), get_top()); check_measure();
return LVecBase4f(_ul2d[0], _lr2d[0], _lr2d[1], _ul2d[1]);
} else if (is_card_as_margin()) { } else if (is_card_as_margin()) {
return LVecBase4f(get_left() - _card_ul[0], check_measure();
get_right() + _card_lr[0], return LVecBase4f(_ul2d[0] - _card_ul[0],
get_bottom() - _card_lr[1], _lr2d[0] + _card_lr[0],
get_top() + _card_ul[1]); _lr2d[1] - _card_lr[1],
_ul2d[1] + _card_ul[1]);
} else { } else {
return get_card_as_set(); return get_card_as_set();
} }
@ -857,7 +815,7 @@ INLINE void TextNode::
set_shadow(float xoffset, float yoffset) { set_shadow(float xoffset, float yoffset) {
_flags |= F_has_shadow; _flags |= F_has_shadow;
_shadow_offset.set(xoffset, yoffset); _shadow_offset.set(xoffset, yoffset);
rebuild(false); invalidate_no_measure();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -869,7 +827,7 @@ set_shadow(float xoffset, float yoffset) {
INLINE void TextNode:: INLINE void TextNode::
clear_shadow() { clear_shadow() {
_flags &= ~F_has_shadow; _flags &= ~F_has_shadow;
rebuild(false); invalidate_no_measure();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -911,7 +869,7 @@ get_shadow() const {
INLINE void TextNode:: INLINE void TextNode::
set_bin(const string &bin) { set_bin(const string &bin) {
_bin = bin; _bin = bin;
rebuild(false); invalidate_no_measure();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -967,7 +925,7 @@ get_bin() const {
INLINE int TextNode:: INLINE int TextNode::
set_draw_order(int draw_order) { set_draw_order(int draw_order) {
_draw_order = draw_order; _draw_order = draw_order;
rebuild(false); invalidate_no_measure();
return _draw_order + 3; return _draw_order + 3;
} }
@ -990,7 +948,7 @@ get_draw_order() const {
INLINE void TextNode:: INLINE void TextNode::
set_transform(const LMatrix4f &transform) { set_transform(const LMatrix4f &transform) {
_transform = transform; _transform = transform;
rebuild(true); invalidate_with_measure();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1012,7 +970,7 @@ get_transform() const {
INLINE void TextNode:: INLINE void TextNode::
set_coordinate_system(CoordinateSystem coordinate_system) { set_coordinate_system(CoordinateSystem coordinate_system) {
_coordinate_system = coordinate_system; _coordinate_system = coordinate_system;
rebuild(true); invalidate_with_measure();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1033,9 +991,11 @@ get_coordinate_system() const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE void TextNode:: INLINE void TextNode::
set_text(const string &text) { set_text(const string &text) {
if (!has_text() || _text != text) {
_text = text; _text = text;
_flags = (_flags | F_got_text) & ~F_got_wtext; _flags = (_flags | F_got_text) & ~F_got_wtext;
rebuild(true); invalidate_with_measure();
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1048,7 +1008,7 @@ clear_text() {
_text = string(); _text = string();
_wtext = wstring(); _wtext = wstring();
_flags |= (F_got_text | F_got_wtext); _flags |= (F_got_text | F_got_wtext);
rebuild(true); invalidate_with_measure();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1089,7 +1049,7 @@ INLINE void TextNode::
append_text(const string &text) { append_text(const string &text) {
_text = get_text() + text; _text = get_text() + text;
_flags = (_flags | F_got_text) & ~F_got_wtext; _flags = (_flags | F_got_text) & ~F_got_wtext;
rebuild(true); invalidate_with_measure();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1103,7 +1063,7 @@ INLINE void TextNode::
append_char(int character) { append_char(int character) {
_wtext = get_wtext() + wstring(1, (wchar_t)character); _wtext = get_wtext() + wstring(1, (wchar_t)character);
_flags = (_flags | F_got_wtext) & ~F_got_text; _flags = (_flags | F_got_wtext) & ~F_got_text;
rebuild(true); invalidate_with_measure();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1159,48 +1119,6 @@ calc_width(const string &line) const {
return _font->calc_width(decode_text(line)); return _font->calc_width(decode_text(line));
} }
////////////////////////////////////////////////////////////////////
// Function: TextNode::rebuild
// Access: Published
// Description: Updates the TextNode, if it is not frozen, or marks
// the TextNode as requiring an update if it is. If the
// text is currently frozen, nothing will be done until
// it is thawed, unless needs_measure is true, in which
// case the text will be re-measured even if it is
// currently frozen.
//
// Normally, this function is called automatically
// whenever any of the parameters changes. It should
// not need to be called explicitly unless something
// goes wrong.
////////////////////////////////////////////////////////////////////
INLINE void TextNode::
rebuild(bool needs_measure) {
if (_freeze_level <= 0) {
do_rebuild();
} else {
_needs_rebuild = true;
if (needs_measure) {
measure();
}
}
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::measure
// Access: Published
// Description: Measures the extent of the text as it will be placed,
// without actually placing it. Normally, this function
// is called automatically whenever any of the
// parameters changes. It should not need to be called
// explicitly unless something goes wrong.
////////////////////////////////////////////////////////////////////
INLINE void TextNode::
measure() {
do_measure();
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::get_left // Function: TextNode::get_left
// Access: Published // Access: Published
@ -1210,6 +1128,7 @@ measure() {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE float TextNode:: INLINE float TextNode::
get_left() const { get_left() const {
check_measure();
return _ul2d[0]; return _ul2d[0];
} }
@ -1222,6 +1141,7 @@ get_left() const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE float TextNode:: INLINE float TextNode::
get_right() const { get_right() const {
check_measure();
return _lr2d[0]; return _lr2d[0];
} }
@ -1234,6 +1154,7 @@ get_right() const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE float TextNode:: INLINE float TextNode::
get_bottom() const { get_bottom() const {
check_measure();
return _lr2d[1]; return _lr2d[1];
} }
@ -1246,6 +1167,7 @@ get_bottom() const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE float TextNode:: INLINE float TextNode::
get_top() const { get_top() const {
check_measure();
return _ul2d[1]; return _ul2d[1];
} }
@ -1257,7 +1179,8 @@ get_top() const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE float TextNode:: INLINE float TextNode::
get_height() const { get_height() const {
return get_top() - get_bottom(); check_measure();
return _ul2d[1] - _lr2d[1];
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1268,7 +1191,8 @@ get_height() const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE float TextNode:: INLINE float TextNode::
get_width() const { get_width() const {
return get_right() - get_left(); check_measure();
return _lr2d[0] - _ul2d[0];
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1280,6 +1204,7 @@ get_width() const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE LPoint3f TextNode:: INLINE LPoint3f TextNode::
get_upper_left_3d() const { get_upper_left_3d() const {
check_measure();
return _ul3d; return _ul3d;
} }
@ -1292,6 +1217,7 @@ get_upper_left_3d() const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE LPoint3f TextNode:: INLINE LPoint3f TextNode::
get_lower_right_3d() const { get_lower_right_3d() const {
check_measure();
return _lr3d; return _lr3d;
} }
@ -1304,9 +1230,23 @@ get_lower_right_3d() const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE int TextNode:: INLINE int TextNode::
get_num_rows() const { get_num_rows() const {
check_measure();
return _num_rows; return _num_rows;
} }
////////////////////////////////////////////////////////////////////
// Function: TextNode::update
// Access: Published
// Description: Can be called after the TextNode has been fully
// configured, to force the node to recompute its text
// immediately, rather than waiting for it to be drawn.
// This call is optional.
////////////////////////////////////////////////////////////////////
INLINE void TextNode::
update() {
check_rebuild();
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::set_wtext // Function: TextNode::set_wtext
// Access: Public // Access: Public
@ -1317,9 +1257,11 @@ get_num_rows() const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE void TextNode:: INLINE void TextNode::
set_wtext(const wstring &wtext) { set_wtext(const wstring &wtext) {
if (!has_text() || _wtext != wtext) {
_wtext = wtext; _wtext = wtext;
_flags = (_flags | F_got_wtext) & ~F_got_text; _flags = (_flags | F_got_wtext) & ~F_got_text;
rebuild(true); invalidate_with_measure();
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1347,7 +1289,7 @@ INLINE void TextNode::
append_wtext(const wstring &wtext) { append_wtext(const wstring &wtext) {
_wtext = get_wtext() + wtext; _wtext = get_wtext() + wtext;
_flags = (_flags | F_got_wtext) & ~F_got_text; _flags = (_flags | F_got_wtext) & ~F_got_text;
rebuild(true); invalidate_with_measure();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1378,3 +1320,60 @@ wordwrap_to(const wstring &wtext, float wordwrap_width,
nassertr(_font != (TextFont *)NULL, wtext); nassertr(_font != (TextFont *)NULL, wtext);
return _font->wordwrap_to(wtext, wordwrap_width, preserve_trailing_whitespace); return _font->wordwrap_to(wtext, wordwrap_width, preserve_trailing_whitespace);
} }
////////////////////////////////////////////////////////////////////
// Function: TextNode::invalidate_no_measure
// Access: Private
// Description: Called internally whenever some state on the TextNode
// changes, requiring the internal geometry to be
// recomputed, but which will not result in a change in
// the size or shape of the text (for instance, the text
// color changes).
////////////////////////////////////////////////////////////////////
INLINE void TextNode::
invalidate_no_measure() {
_flags |= F_needs_rebuild;
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::invalidate_with_measure
// Access: Private
// Description: Called internally whenever some state on the TextNode
// changes, requiring the internal geometry to be
// recomputed, and which will may result in a change in
// the size or shape of the text (for instance, the text
// scale changes).
////////////////////////////////////////////////////////////////////
INLINE void TextNode::
invalidate_with_measure() {
_flags |= (F_needs_rebuild | F_needs_measure);
mark_bound_stale();
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::check_rebuild
// Access: Private
// Description: Called internally to call do_rebuild() if necessary
// (that is, if the internal geometry has changed
// recently).
////////////////////////////////////////////////////////////////////
INLINE void TextNode::
check_rebuild() const {
if ((_flags & F_needs_rebuild) != 0) {
((TextNode *)this)->do_rebuild();
}
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::check_measure
// Access: Private
// Description: Called internally to call do_measure() if necessary;
// this will remeasure the text without necessarily
// rebuilding it.
////////////////////////////////////////////////////////////////////
INLINE void TextNode::
check_measure() const {
if ((_flags & F_needs_measure) != 0) {
((TextNode *)this)->do_measure();
}
}

View File

@ -30,11 +30,17 @@
#include "notify.h" #include "notify.h"
#include "transformState.h" #include "transformState.h"
#include "colorAttrib.h" #include "colorAttrib.h"
#include "colorScaleAttrib.h"
#include "cullBinAttrib.h" #include "cullBinAttrib.h"
#include "textureAttrib.h" #include "textureAttrib.h"
#include "transparencyAttrib.h" #include "transparencyAttrib.h"
#include "sceneGraphReducer.h" #include "sceneGraphReducer.h"
#include "indent.h" #include "indent.h"
#include "cullTraverser.h"
#include "cullTraverserData.h"
#include "geometricBoundingVolume.h"
#include "accumulatedAttribs.h"
#include "dcast.h"
#include <stdio.h> #include <stdio.h>
#include <ctype.h> #include <ctype.h>
@ -83,9 +89,6 @@ TextNode(const string &name) : PandaNode(name) {
_ul3d.set(0.0f, 0.0f, 0.0f); _ul3d.set(0.0f, 0.0f, 0.0f);
_lr3d.set(0.0f, 0.0f, 0.0f); _lr3d.set(0.0f, 0.0f, 0.0f);
_num_rows = 0; _num_rows = 0;
_freeze_level = 0;
_needs_rebuild = false;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -302,6 +305,9 @@ generate() {
_ul3d = _ul3d * _transform; _ul3d = _ul3d * _transform;
_lr3d = _lr3d * _transform; _lr3d = _lr3d * _transform;
// Incidentally, that means we don't need to measure the text now.
_flags &= ~F_needs_measure;
// Now deal with all the decorations. // Now deal with all the decorations.
@ -462,15 +468,212 @@ decode_text(const string &text) const {
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::xform // Function: TextNode::get_unsafe_to_apply_attribs
// Access: Public, Virtual // Access: Public, Virtual
// Description: Transforms the contents of this PandaNode by the // Description: Returns the union of all attributes from
// indicated matrix, if it means anything to do so. For // SceneGraphReducer::AttribTypes that may not safely be
// most kinds of PandaNodes, this does nothing. // applied to the vertices of this node. If this is
// nonzero, these attributes must be dropped at this
// node as a state change.
//
// This is a generalization of safe_to_transform().
////////////////////////////////////////////////////////////////////
int TextNode::
get_unsafe_to_apply_attribs() const {
// We have no way to apply these kinds of attributes to our
// TextNode, so insist they get dropped into the PandaNode's basic
// state.
return
SceneGraphReducer::TT_tex_matrix |
SceneGraphReducer::TT_other;
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::apply_attribs_to_vertices
// Access: Public, Virtual
// Description: Applies whatever attributes are specified in the
// AccumulatedAttribs object (and by the attrib_types
// bitmask) to the vertices on this node, if
// appropriate. If this node uses geom arrays like a
// GeomNode, the supplied GeomTransformer may be used to
// unify shared arrays across multiple different nodes.
//
// This is a generalization of xform().
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void TextNode:: void TextNode::
xform(const LMatrix4f &mat) { apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types,
GeomTransformer &transformer) {
if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
const LMatrix4f &mat = attribs._transform->get_mat();
_transform *= mat; _transform *= mat;
if ((_flags & F_needs_measure) == 0) {
// If we already have a measure, transform it too. We don't
// need to invalidate the 2-d parts, since that's not affected
// by the transform anyway.
_ul3d = _ul3d * mat;
_lr3d = _lr3d * mat;
}
}
if ((attrib_types & SceneGraphReducer::TT_color) != 0) {
if (attribs._color != (const RenderAttrib *)NULL) {
const ColorAttrib *ca = DCAST(ColorAttrib, attribs._color);
if (ca->get_color_type() == ColorAttrib::T_flat) {
const Colorf &c = ca->get_color();
_text_color = c;
_frame_color = c;
_card_color = c;
_shadow_color = c;
_flags |= F_has_text_color;
}
}
}
if ((attrib_types & SceneGraphReducer::TT_color_scale) != 0) {
if (attribs._color_scale != (const RenderAttrib *)NULL) {
const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attribs._color_scale);
const LVecBase4f &s = csa->get_scale();
if (s != LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f)) {
_text_color[0] *= s[0];
_text_color[1] *= s[1];
_text_color[2] *= s[2];
_text_color[3] *= s[3];
_frame_color[0] *= s[0];
_frame_color[1] *= s[1];
_frame_color[2] *= s[2];
_frame_color[3] *= s[3];
_card_color[0] *= s[0];
_card_color[1] *= s[1];
_card_color[2] *= s[2];
_card_color[3] *= s[3];
_shadow_color[0] *= s[0];
_shadow_color[1] *= s[1];
_shadow_color[2] *= s[2];
_shadow_color[3] *= s[3];
}
}
}
// Now propagate the attributes down to our already-generated
// geometry, if we have any.
if ((_flags & F_needs_rebuild) == 0 &&
_internal_geom != (PandaNode *)NULL) {
SceneGraphReducer gr;
gr.apply_attribs(_internal_geom, attribs, attrib_types, transformer);
}
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::calc_tight_bounds
// Access: Public, Virtual
// Description: This is used to support
// NodePath::calc_tight_bounds(). It is not intended to
// be called directly, and it has nothing to do with the
// normal Panda bounding-volume computation.
//
// If the node contains any geometry, this updates
// min_point and max_point to enclose its bounding box.
// found_any is to be set true if the node has any
// geometry at all, or left alone if it has none. This
// method may be called over several nodes, so it may
// enter with min_point, max_point, and found_any
// already set.
////////////////////////////////////////////////////////////////////
CPT(TransformState) TextNode::
calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any,
const TransformState *transform) const {
CPT(TransformState) next_transform =
PandaNode::calc_tight_bounds(min_point, max_point, found_any, transform);
check_rebuild();
if (_internal_geom != (PandaNode *)NULL) {
_internal_geom->calc_tight_bounds(min_point, max_point,
found_any, next_transform);
}
return next_transform;
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::has_cull_callback
// Access: Protected, Virtual
// Description: Should be overridden by derived classes to return
// true if cull_callback() has been defined. Otherwise,
// returns false to indicate cull_callback() does not
// need to be called for this node during the cull
// traversal.
////////////////////////////////////////////////////////////////////
bool TextNode::
has_cull_callback() const {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::cull_callback
// Access: Protected, Virtual
// Description: If has_cull_callback() returns true, this function
// will be called during the cull traversal to perform
// any additional operations that should be performed at
// cull time. This may include additional manipulation
// of render state or additional visible/invisible
// decisions, or any other arbitrary operation.
//
// By the time this function is called, the node has
// already passed the bounding-volume test for the
// viewing frustum, and the node's transform and state
// have already been applied to the indicated
// CullTraverserData object.
//
// The return value is true if this node should be
// visible, or false if it should be culled.
////////////////////////////////////////////////////////////////////
bool TextNode::
cull_callback(CullTraverser *trav, CullTraverserData &data) {
check_rebuild();
if (_internal_geom != (PandaNode *)NULL) {
// Render the text with this node.
CullTraverserData next_data(data, _internal_geom);
trav->traverse(next_data);
}
// Now continue to render everything else below this node.
return true;
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::recompute_internal_bound
// Access: Protected, Virtual
// Description: Called when needed to recompute the node's
// _internal_bound object. Nodes that contain anything
// of substance should redefine this to do the right
// thing.
////////////////////////////////////////////////////////////////////
BoundingVolume *TextNode::
recompute_internal_bound() {
// First, get ourselves a fresh, empty bounding volume.
BoundingVolume *bound = PandaNode::recompute_internal_bound();
nassertr(bound != (BoundingVolume *)NULL, bound);
GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, bound);
// Now enclose the bounding box around the text. We can do this
// without actually generating the text, if we have at least
// measured it.
check_measure();
LPoint3f vertices[8];
vertices[0].set(_ul3d[0], _ul3d[1], _ul3d[2]);
vertices[1].set(_ul3d[0], _ul3d[1], _lr3d[2]);
vertices[2].set(_ul3d[0], _lr3d[1], _ul3d[2]);
vertices[3].set(_ul3d[0], _lr3d[1], _lr3d[2]);
vertices[4].set(_lr3d[0], _ul3d[1], _ul3d[2]);
vertices[5].set(_lr3d[0], _ul3d[1], _lr3d[2]);
vertices[6].set(_lr3d[0], _lr3d[1], _ul3d[2]);
vertices[7].set(_lr3d[0], _lr3d[1], _lr3d[2]);
gbv->around(vertices, vertices + 8);
return bound;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -596,23 +799,8 @@ expand_amp_sequence(StringDecoder &decoder) const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void TextNode:: void TextNode::
do_rebuild() { do_rebuild() {
_needs_rebuild = false; _flags &= ~(F_needs_rebuild | F_needs_measure);
_internal_geom = generate();
remove_all_children();
PT(PandaNode) new_text = generate();
if (new_text != (PandaNode *)NULL) {
add_child(new_text);
/*
// And we flatten one more time, to remove the new node itself if
// possible (it might be an unneeded node above multiple
// children). This flatten operation should be fairly
// lightweight; it's already pretty flat.
SceneGraphReducer gr(RenderRelation::get_class_type());
gr.flatten(this, false);
*/
}
} }
@ -625,6 +813,8 @@ do_rebuild() {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void TextNode:: void TextNode::
do_measure() { do_measure() {
_flags &= ~F_needs_measure;
_ul2d.set(0.0f, 0.0f); _ul2d.set(0.0f, 0.0f);
_lr2d.set(0.0f, 0.0f); _lr2d.set(0.0f, 0.0f);
_ul3d.set(0.0f, 0.0f, 0.0f); _ul3d.set(0.0f, 0.0f, 0.0f);

View File

@ -38,22 +38,19 @@ class StringDecoder;
// represent the indicated text. // represent the indicated text.
// //
// The TextNode may be used in one of two ways. // The TextNode may be used in one of two ways.
// Naively, it may be parented to the scene graph // Naively, it may simply be parented directly into the
// directly; used in this way, you can optionally call // scene graph and rendered as if it were a GeomNode; in
// freeze() and thaw() between changing many parameters // this mode, the actual polygon geometry that renders
// in the text at once, to avoid unnecessary expensive // the text is not directly visible or accessible, but
// regeneration with each parameter change. However, it // remains hidden within the TextNode.
// will work, if slowly, even if you never call freeze()
// and thaw().
// //
// The second way TextNode may be used is as a text // The second way TextNode may be used is as a text
// generator. To use it in this way, call freeze() once // generator. To use it in this way, do not parent the
// on the TextNode when you create it, and never call // TextNode to the scene graph; instead, set the
// thaw(). Do not parent the TextNode to the scene // properties of the text and call generate() to return
// graph; instea, set the properties of the text and // an ordinary node, containing ordinary geometry, which
// call generate() to return a node which you may parent // you may use however you like. Each time you call
// wherever you like. Each time you call generate() a // generate() a new node is returned.
// new node is returned.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
class EXPCL_PANDA TextNode : public PandaNode { class EXPCL_PANDA TextNode : public PandaNode {
PUBLISHED: PUBLISHED:
@ -73,7 +70,6 @@ PUBLISHED:
}; };
INLINE int freeze(); INLINE int freeze();
INLINE int get_freeze_level() const;
INLINE int thaw(); INLINE int thaw();
INLINE void set_font(TextFont *font); INLINE void set_font(TextFont *font);
@ -188,9 +184,6 @@ PUBLISHED:
virtual void write(ostream &out, int indent_level = 0) const; virtual void write(ostream &out, int indent_level = 0) const;
INLINE void rebuild(bool needs_measure);
INLINE void measure();
// The following functions return information about the text that // The following functions return information about the text that
// was last built (and is currently visible). // was last built (and is currently visible).
INLINE float get_left() const; INLINE float get_left() const;
@ -206,6 +199,7 @@ PUBLISHED:
INLINE int get_num_rows() const; INLINE int get_num_rows() const;
PT(PandaNode) generate(); PT(PandaNode) generate();
INLINE void update();
public: public:
// Direct support for wide-character strings. // Direct support for wide-character strings.
@ -222,12 +216,29 @@ public:
wstring decode_text(const string &text) const; wstring decode_text(const string &text) const;
// From parent class PandaNode // From parent class PandaNode
virtual void xform(const LMatrix4f &mat); virtual int get_unsafe_to_apply_attribs() const;
virtual void apply_attribs_to_vertices(const AccumulatedAttribs &attribs,
int attrib_types,
GeomTransformer &transformer);
virtual CPT(TransformState)
calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
bool &found_any,
const TransformState *transform) const;
virtual bool has_cull_callback() const;
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data);
virtual BoundingVolume *recompute_internal_bound();
private: private:
wstring decode_text_impl(StringDecoder &decoder) const; wstring decode_text_impl(StringDecoder &decoder) const;
int expand_amp_sequence(StringDecoder &decoder) const; int expand_amp_sequence(StringDecoder &decoder) const;
INLINE void invalidate_no_measure();
INLINE void invalidate_with_measure();
INLINE void check_rebuild() const;
INLINE void check_measure() const;
void do_rebuild(); void do_rebuild();
void do_measure(); void do_measure();
@ -246,6 +257,7 @@ private:
PT(PandaNode) make_card_with_border(); PT(PandaNode) make_card_with_border();
PT(TextFont) _font; PT(TextFont) _font;
PT(PandaNode) _internal_geom;
Encoding _encoding; Encoding _encoding;
float _slant; float _slant;
@ -271,6 +283,8 @@ private:
F_expand_amp = 0x0800, F_expand_amp = 0x0800,
F_got_text = 0x1000, F_got_text = 0x1000,
F_got_wtext = 0x2000, F_got_wtext = 0x2000,
F_needs_rebuild = 0x4000,
F_needs_measure = 0x8000,
}; };
int _flags; int _flags;
@ -296,8 +310,6 @@ private:
LPoint2f _ul2d, _lr2d; LPoint2f _ul2d, _lr2d;
LPoint3f _ul3d, _lr3d; LPoint3f _ul3d, _lr3d;
int _num_rows; int _num_rows;
int _freeze_level;
bool _needs_rebuild;
public: public:
static Encoding _default_encoding; static Encoding _default_encoding;