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 SOURCES \
accumulatedAttribs.I accumulatedAttribs.h \
alphaTestAttrib.I alphaTestAttrib.h \
ambientLight.I ambientLight.h \
bamFile.I bamFile.h \
@ -91,6 +92,7 @@
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
#define INCLUDED_SOURCES \
accumulatedAttribs.cxx \
alphaTestAttrib.cxx \
ambientLight.cxx \
bamFile.cxx \
@ -173,6 +175,7 @@
workingNodePath.cxx
#define INSTALL_HEADERS \
accumulatedAttribs.I accumulatedAttribs.h \
alphaTestAttrib.I alphaTestAttrib.h \
ambientLight.I ambientLight.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 "geomTransformer.h"
#include "sceneGraphReducer.h"
#include "accumulatedAttribs.h"
#include "bamReader.h"
#include "bamWriter.h"
#include "datagram.h"
@ -154,6 +156,62 @@ make_copy() const {
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
// Access: Public, Virtual
@ -200,6 +258,59 @@ combine_with(PandaNode *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
// Access: Published

View File

@ -44,8 +44,15 @@ protected:
public:
virtual ~GeomNode();
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 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:
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);
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());
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
// Access: Private

View File

@ -542,9 +542,6 @@ private:
void r_adjust_all_priorities(PandaNode *node, int adjustment);
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;
Texture *r_find_texture(PandaNode *node, const RenderState *state,

View File

@ -23,6 +23,8 @@
#include "bamWriter.h"
#include "indent.h"
#include "geometricBoundingVolume.h"
#include "sceneGraphReducer.h"
#include "accumulatedAttribs.h"
TypeHandle PandaNode::_type_handle;
@ -501,6 +503,18 @@ safe_to_combine() const {
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
// Access: Public, Virtual
@ -513,6 +527,42 @@ preserve_name() const {
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
// Access: Public, Virtual
@ -568,6 +618,41 @@ combine_with(PandaNode *other) {
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
// Access: Public, Virtual

View File

@ -45,6 +45,8 @@ class CullTraverser;
class CullTraverserData;
class Light;
class FactoryParams;
class AccumulatedAttribs;
class GeomTransformer;
////////////////////////////////////////////////////////////////////
// Class : PandaNode
@ -71,9 +73,18 @@ public:
virtual bool safe_to_transform() const;
virtual bool safe_to_modify_transform() const;
virtual bool safe_to_combine() const;
virtual bool safe_to_flatten_below() 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 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 cull_callback(CullTraverser *trav, CullTraverserData &data);

View File

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

View File

@ -18,39 +18,58 @@
////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::AccumulatedAttribs::Constructor
// Access: Public
// Function: SceneGraphReducer::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE SceneGraphReducer::AccumulatedAttribs::
AccumulatedAttribs() {
INLINE SceneGraphReducer::
SceneGraphReducer() {
}
////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::AccumulatedAttribs::Copy Constructor
// Access: Public
// Function: SceneGraphReducer::Destructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE SceneGraphReducer::AccumulatedAttribs::
AccumulatedAttribs(const SceneGraphReducer::AccumulatedAttribs &copy) :
_transform(copy._transform),
_color(copy._color),
_color_scale(copy._color_scale),
_tex_matrix(copy._tex_matrix),
_other(copy._other)
{
INLINE SceneGraphReducer::
~SceneGraphReducer() {
}
////////////////////////////////////////////////////////////////////
// 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
// Access: Public
// Description:
// Function: SceneGraphReducer::apply_attribs
// Access: Published
// 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::
operator = (const SceneGraphReducer::AccumulatedAttribs &copy) {
_transform = copy._transform;
_color = copy._color;
_color_scale = copy._color_scale;
_tex_matrix = copy._tex_matrix;
_other = copy._other;
INLINE void SceneGraphReducer::
apply_attribs(PandaNode *node, const AccumulatedAttribs &attribs,
int attrib_types, GeomTransformer &transformer) {
r_apply_attribs(node, attribs, attrib_types, transformer);
}

View File

@ -21,6 +21,7 @@
#include "colorAttrib.h"
#include "texMatrixAttrib.h"
#include "colorScaleAttrib.h"
#include "accumulatedAttribs.h"
#include "geomNode.h"
#include "pointerTo.h"
@ -28,292 +29,15 @@
#include "indent.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
// Access: Public
// Access: Published
// Description: Simplifies the graph by removing unnecessary nodes
// and nodes.
//
// In general, a node (and its parent node) is a
// candidate for removal if the node has no siblings and
// the node and node have no special properties. The
// definition of what, precisely, is a 'special
// property' may be extended by subclassing from this
// type and redefining consider_node() appropriately.
// the node has no special properties.
//
// If combine_siblings is true, sibling nodes may also
// 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().
////////////////////////////////////////////////////////////////////
void SceneGraphReducer::
r_apply_attribs(PandaNode *node, int attrib_types,
SceneGraphReducer::AccumulatedAttribs trans) {
r_apply_attribs(PandaNode *node, const AccumulatedAttribs &attribs,
int attrib_types, GeomTransformer &transformer) {
if (pgraph_cat.is_debug()) {
pgraph_cat.debug()
<< "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);
}
trans.collect(node, attrib_types);
AccumulatedAttribs next_attribs(attribs);
next_attribs.collect(node, attrib_types);
if (pgraph_cat.is_debug()) {
pgraph_cat.debug()
<< "Got attribs from " << *node << "\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
@ -405,6 +130,7 @@ r_apply_attribs(PandaNode *node, int attrib_types,
}
apply_types |= TT_transform;
}
apply_types |= node->get_unsafe_to_apply_attribs();
// Also, check the children of this node. If any of them indicates
// 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,
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.
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?
bool resist_copy = false;
@ -473,14 +199,14 @@ r_apply_attribs(PandaNode *node, int attrib_types,
if (resist_copy) {
// If any of our children should have been copied but weren't, we
// 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.
nassertv(num_children == node->get_num_children());
for (i = 0; i < num_children; 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
// Access: Protected, Virtual
// Access: Protected
// Description: Decides whether or not the indicated child node is a
// suitable candidate for removal. Returns true if the
// node may be removed, false if it should be kept. This
// function may be extended in a user class to protect
// special kinds of nodes from deletion.
// node may be removed, false if it should be kept.
////////////////////////////////////////////////////////////////////
bool SceneGraphReducer::
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
// Access: Protected, Virtual
// Access: Protected
// Description: Decides whether or not the indicated sibling nodes
// should be collapsed into a single node or not.
// 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
// Access: Protected, Virtual
// Access: Protected
// Description: Collapses together the indicated parent node and
// child node and leaves the result attached to the
// grandparent. The return value is true if the node is
// successfully collapsed, false if we chickened out.
//
// This function may be extended in a user class to
// handle special kinds of nodes.
////////////////////////////////////////////////////////////////////
bool SceneGraphReducer::
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
// Access: Protected, Virtual
// Access: Protected
// Description: Performs the work of collapsing two sibling nodes
// together into a single node, leaving the resulting
// node attached to the parent.
@ -779,7 +500,7 @@ do_flatten_siblings(PandaNode *parent_node, PandaNode *child1,
////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::collapse_nodes
// Access: Protected, Virtual
// Access: Protected
// Description: Collapses the two nodes into a single node, if
// possible. The 'siblings' flag is true if the two
// 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
// a new node altogether, or it may be NULL to indicate
// 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::
collapse_nodes(PandaNode *node1, PandaNode *node2, bool siblings) {
@ -799,7 +517,7 @@ collapse_nodes(PandaNode *node1, PandaNode *node2, bool siblings) {
////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::choose_name
// Access: Protected, Virtual
// Access: Protected
// Description: Chooses a suitable name for the collapsed node, based
// on the names of the two sources nodes.
////////////////////////////////////////////////////////////////////

View File

@ -23,11 +23,14 @@
#include "transformState.h"
#include "renderAttrib.h"
#include "renderState.h"
#include "accumulatedAttribs.h"
#include "geomTransformer.h"
#include "typedObject.h"
#include "pointerTo.h"
class PandaNode;
///////////////////////////////////////////////////////////////////
// Class : SceneGraphReducer
// Description : An interface for simplifying ("flattening") scene
@ -41,8 +44,8 @@
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA SceneGraphReducer {
PUBLISHED:
SceneGraphReducer();
virtual ~SceneGraphReducer();
INLINE SceneGraphReducer();
INLINE ~SceneGraphReducer();
enum AttribTypes {
TT_transform = 0x001,
@ -52,52 +55,34 @@ PUBLISHED:
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);
protected:
class 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);
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);
void r_apply_attribs(PandaNode *node, const AccumulatedAttribs &attribs,
int attrib_types, GeomTransformer &transformer);
int r_flatten(PandaNode *grandparent_node, PandaNode *parent_node,
bool combine_siblings);
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);
virtual bool consider_siblings(PandaNode *parent_node, PandaNode *child1,
bool consider_siblings(PandaNode *parent_node, PandaNode *child1,
PandaNode *child2);
virtual bool do_flatten_child(PandaNode *grandparent_node,
bool do_flatten_child(PandaNode *grandparent_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);
virtual PT(PandaNode) collapse_nodes(PandaNode *node1, PandaNode *node2,
PT(PandaNode) collapse_nodes(PandaNode *node1, PandaNode *node2,
bool siblings);
virtual void choose_name(PandaNode *preserve, PandaNode *source1,
void choose_name(PandaNode *preserve, PandaNode *source1,
PandaNode *source2);
private:

View File

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

View File

@ -20,70 +20,25 @@
////////////////////////////////////////////////////////////////////
// Function: TextNode::freeze
// Access: Published
// Description: Freezes the TextNode in its current state, so that
// updates will not immediately be displayed. A series
// of state changes may then be applied in succession,
// 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().
// Description: This method is deprecated and no longer does
// anything. It is included for historical purposes
// only and will shortly be removed.
////////////////////////////////////////////////////////////////////
INLINE int TextNode::
freeze() {
if (text_cat.is_debug()) {
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;
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::thaw
// Access: Published
// Description: Allows changes made since the last freeze() to be
// visible. Strictly speaking, this actually decrements
// the freeze level, and updates the TextNode if the
// level reaches zero. The return value is the new
// freeze level after adjusting. See freeze().
// Description: This method is deprecated and no longer does
// anything. It is included for historical purposes
// only and will shortly be removed.
////////////////////////////////////////////////////////////////////
INLINE int TextNode::
thaw() {
if (text_cat.is_debug()) {
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;
return 0;
}
////////////////////////////////////////////////////////////////////
@ -95,7 +50,7 @@ INLINE void TextNode::
set_font(TextFont *font) {
if (_font != font) {
_font = font;
rebuild(true);
invalidate_with_measure();
}
}
@ -193,7 +148,7 @@ INLINE void TextNode::
set_slant(float slant) {
if (_slant != slant) {
_slant = slant;
rebuild(true);
invalidate_with_measure();
}
}
@ -216,7 +171,7 @@ INLINE void TextNode::
set_align(TextNode::Alignment align_type) {
if (_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) {
_flags |= F_has_wordwrap;
_wordwrap_width = wordwrap;
rebuild(true);
invalidate_with_measure();
}
}
@ -255,7 +210,7 @@ INLINE void TextNode::
clear_wordwrap() {
if (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) {
_text_color = text_color;
_flags |= F_has_text_color;
rebuild(false);
invalidate_no_measure();
}
}
@ -313,7 +268,7 @@ INLINE void TextNode::
clear_text_color() {
if (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) {
if (_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;
_card_border_size = size;
_card_border_uv_portion = uv_portion;
rebuild(false);
invalidate_no_measure();
}
}
@ -394,7 +349,7 @@ INLINE void TextNode::
clear_card_border() {
if (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) {
if (_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) {
_flags |= F_has_card_texture;
_card_texture = card_texture;
rebuild(false);
invalidate_no_measure();
}
}
}
@ -489,7 +444,7 @@ clear_card_texture() {
if (has_card_texture()) {
_flags &= ~F_has_card_texture;
_card_texture = NULL;
rebuild(false);
invalidate_no_measure();
}
}
@ -532,7 +487,7 @@ INLINE void TextNode::
set_shadow_color(const Colorf &shadow_color) {
if (_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);
_frame_ul.set(left, top);
_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;
_frame_ul.set(left, top);
_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::
clear_frame() {
_flags &= ~F_has_frame;
rebuild(false);
invalidate_no_measure();
}
////////////////////////////////////////////////////////////////////
@ -650,10 +605,11 @@ INLINE LVecBase4f TextNode::
get_frame_actual() const {
nassertr(has_frame(), LVecBase4f(0.0, 0.0, 0.0, 0.0));
if (is_frame_as_margin()) {
return LVecBase4f(get_left() - _frame_ul[0],
get_right() + _frame_lr[0],
get_bottom() - _frame_lr[1],
get_top() + _frame_ul[1]);
check_measure();
return LVecBase4f(_ul2d[0] - _frame_ul[0],
_lr2d[0] + _frame_lr[0],
_lr2d[1] - _frame_lr[1],
_ul2d[1] + _frame_ul[1]);
} else {
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);
_card_ul.set(left, top);
_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;
_card_ul.set(left, top);
_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::
clear_card() {
_flags &= ~F_has_card;
rebuild(false);
invalidate_no_measure();
}
////////////////////////////////////////////////////////////////////
@ -816,13 +772,15 @@ get_card_as_set() const {
INLINE LVecBase4f TextNode::
get_card_actual() const {
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()) {
return LVecBase4f(get_left() - _card_ul[0],
get_right() + _card_lr[0],
get_bottom() - _card_lr[1],
get_top() + _card_ul[1]);
check_measure();
return LVecBase4f(_ul2d[0] - _card_ul[0],
_lr2d[0] + _card_lr[0],
_lr2d[1] - _card_lr[1],
_ul2d[1] + _card_ul[1]);
} else {
return get_card_as_set();
}
@ -857,7 +815,7 @@ INLINE void TextNode::
set_shadow(float xoffset, float yoffset) {
_flags |= F_has_shadow;
_shadow_offset.set(xoffset, yoffset);
rebuild(false);
invalidate_no_measure();
}
////////////////////////////////////////////////////////////////////
@ -869,7 +827,7 @@ set_shadow(float xoffset, float yoffset) {
INLINE void TextNode::
clear_shadow() {
_flags &= ~F_has_shadow;
rebuild(false);
invalidate_no_measure();
}
////////////////////////////////////////////////////////////////////
@ -911,7 +869,7 @@ get_shadow() const {
INLINE void TextNode::
set_bin(const string &bin) {
_bin = bin;
rebuild(false);
invalidate_no_measure();
}
////////////////////////////////////////////////////////////////////
@ -967,7 +925,7 @@ get_bin() const {
INLINE int TextNode::
set_draw_order(int draw_order) {
_draw_order = draw_order;
rebuild(false);
invalidate_no_measure();
return _draw_order + 3;
}
@ -990,7 +948,7 @@ get_draw_order() const {
INLINE void TextNode::
set_transform(const LMatrix4f &transform) {
_transform = transform;
rebuild(true);
invalidate_with_measure();
}
////////////////////////////////////////////////////////////////////
@ -1012,7 +970,7 @@ get_transform() const {
INLINE void TextNode::
set_coordinate_system(CoordinateSystem coordinate_system) {
_coordinate_system = coordinate_system;
rebuild(true);
invalidate_with_measure();
}
////////////////////////////////////////////////////////////////////
@ -1033,9 +991,11 @@ get_coordinate_system() const {
////////////////////////////////////////////////////////////////////
INLINE void TextNode::
set_text(const string &text) {
if (!has_text() || _text != text) {
_text = text;
_flags = (_flags | F_got_text) & ~F_got_wtext;
rebuild(true);
invalidate_with_measure();
}
}
////////////////////////////////////////////////////////////////////
@ -1048,7 +1008,7 @@ clear_text() {
_text = string();
_wtext = wstring();
_flags |= (F_got_text | F_got_wtext);
rebuild(true);
invalidate_with_measure();
}
////////////////////////////////////////////////////////////////////
@ -1089,7 +1049,7 @@ INLINE void TextNode::
append_text(const string &text) {
_text = get_text() + text;
_flags = (_flags | F_got_text) & ~F_got_wtext;
rebuild(true);
invalidate_with_measure();
}
////////////////////////////////////////////////////////////////////
@ -1103,7 +1063,7 @@ INLINE void TextNode::
append_char(int character) {
_wtext = get_wtext() + wstring(1, (wchar_t)character);
_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));
}
////////////////////////////////////////////////////////////////////
// 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
// Access: Published
@ -1210,6 +1128,7 @@ measure() {
////////////////////////////////////////////////////////////////////
INLINE float TextNode::
get_left() const {
check_measure();
return _ul2d[0];
}
@ -1222,6 +1141,7 @@ get_left() const {
////////////////////////////////////////////////////////////////////
INLINE float TextNode::
get_right() const {
check_measure();
return _lr2d[0];
}
@ -1234,6 +1154,7 @@ get_right() const {
////////////////////////////////////////////////////////////////////
INLINE float TextNode::
get_bottom() const {
check_measure();
return _lr2d[1];
}
@ -1246,6 +1167,7 @@ get_bottom() const {
////////////////////////////////////////////////////////////////////
INLINE float TextNode::
get_top() const {
check_measure();
return _ul2d[1];
}
@ -1257,7 +1179,8 @@ get_top() const {
////////////////////////////////////////////////////////////////////
INLINE float TextNode::
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::
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::
get_upper_left_3d() const {
check_measure();
return _ul3d;
}
@ -1292,6 +1217,7 @@ get_upper_left_3d() const {
////////////////////////////////////////////////////////////////////
INLINE LPoint3f TextNode::
get_lower_right_3d() const {
check_measure();
return _lr3d;
}
@ -1304,9 +1230,23 @@ get_lower_right_3d() const {
////////////////////////////////////////////////////////////////////
INLINE int TextNode::
get_num_rows() const {
check_measure();
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
// Access: Public
@ -1317,9 +1257,11 @@ get_num_rows() const {
////////////////////////////////////////////////////////////////////
INLINE void TextNode::
set_wtext(const wstring &wtext) {
if (!has_text() || _wtext != wtext) {
_wtext = wtext;
_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) {
_wtext = get_wtext() + wtext;
_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);
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 "transformState.h"
#include "colorAttrib.h"
#include "colorScaleAttrib.h"
#include "cullBinAttrib.h"
#include "textureAttrib.h"
#include "transparencyAttrib.h"
#include "sceneGraphReducer.h"
#include "indent.h"
#include "cullTraverser.h"
#include "cullTraverserData.h"
#include "geometricBoundingVolume.h"
#include "accumulatedAttribs.h"
#include "dcast.h"
#include <stdio.h>
#include <ctype.h>
@ -83,9 +89,6 @@ TextNode(const string &name) : PandaNode(name) {
_ul3d.set(0.0f, 0.0f, 0.0f);
_lr3d.set(0.0f, 0.0f, 0.0f);
_num_rows = 0;
_freeze_level = 0;
_needs_rebuild = false;
}
////////////////////////////////////////////////////////////////////
@ -302,6 +305,9 @@ generate() {
_ul3d = _ul3d * _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.
@ -462,15 +468,212 @@ decode_text(const string &text) const {
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::xform
// Function: TextNode::get_unsafe_to_apply_attribs
// Access: Public, Virtual
// Description: Transforms the contents of this PandaNode by the
// indicated matrix, if it means anything to do so. For
// most kinds of PandaNodes, this does nothing.
// 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 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::
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;
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::
do_rebuild() {
_needs_rebuild = false;
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);
*/
}
_flags &= ~(F_needs_rebuild | F_needs_measure);
_internal_geom = generate();
}
@ -625,6 +813,8 @@ do_rebuild() {
////////////////////////////////////////////////////////////////////
void TextNode::
do_measure() {
_flags &= ~F_needs_measure;
_ul2d.set(0.0f, 0.0f);
_lr2d.set(0.0f, 0.0f);
_ul3d.set(0.0f, 0.0f, 0.0f);

View File

@ -38,22 +38,19 @@ class StringDecoder;
// represent the indicated text.
//
// The TextNode may be used in one of two ways.
// Naively, it may be parented to the scene graph
// directly; used in this way, you can optionally call
// freeze() and thaw() between changing many parameters
// in the text at once, to avoid unnecessary expensive
// regeneration with each parameter change. However, it
// will work, if slowly, even if you never call freeze()
// and thaw().
// Naively, it may simply be parented directly into the
// scene graph and rendered as if it were a GeomNode; in
// this mode, the actual polygon geometry that renders
// the text is not directly visible or accessible, but
// remains hidden within the TextNode.
//
// The second way TextNode may be used is as a text
// generator. To use it in this way, call freeze() once
// on the TextNode when you create it, and never call
// thaw(). Do not parent the TextNode to the scene
// graph; instea, set the properties of the text and
// call generate() to return a node which you may parent
// wherever you like. Each time you call generate() a
// new node is returned.
// generator. To use it in this way, do not parent the
// TextNode to the scene graph; instead, set the
// properties of the text and call generate() to return
// an ordinary node, containing ordinary geometry, which
// you may use however you like. Each time you call
// generate() a new node is returned.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA TextNode : public PandaNode {
PUBLISHED:
@ -73,7 +70,6 @@ PUBLISHED:
};
INLINE int freeze();
INLINE int get_freeze_level() const;
INLINE int thaw();
INLINE void set_font(TextFont *font);
@ -188,9 +184,6 @@ PUBLISHED:
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
// was last built (and is currently visible).
INLINE float get_left() const;
@ -206,6 +199,7 @@ PUBLISHED:
INLINE int get_num_rows() const;
PT(PandaNode) generate();
INLINE void update();
public:
// Direct support for wide-character strings.
@ -222,12 +216,29 @@ public:
wstring decode_text(const string &text) const;
// 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:
wstring decode_text_impl(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_measure();
@ -246,6 +257,7 @@ private:
PT(PandaNode) make_card_with_border();
PT(TextFont) _font;
PT(PandaNode) _internal_geom;
Encoding _encoding;
float _slant;
@ -271,6 +283,8 @@ private:
F_expand_amp = 0x0800,
F_got_text = 0x1000,
F_got_wtext = 0x2000,
F_needs_rebuild = 0x4000,
F_needs_measure = 0x8000,
};
int _flags;
@ -296,8 +310,6 @@ private:
LPoint2f _ul2d, _lr2d;
LPoint3f _ul3d, _lr3d;
int _num_rows;
int _freeze_level;
bool _needs_rebuild;
public:
static Encoding _default_encoding;