16 #include "textGlyph.h"
17 #include "stringDecoder.h"
18 #include "config_text.h"
19 #include "textAssembler.h"
21 #include "compose_matrix.h"
23 #include "geomLinestrips.h"
24 #include "geomPoints.h"
25 #include "geomTristrips.h"
26 #include "geomVertexWriter.h"
29 #include "transformState.h"
30 #include "colorAttrib.h"
31 #include "colorScaleAttrib.h"
32 #include "cullBinAttrib.h"
33 #include "textureAttrib.h"
34 #include "transparencyAttrib.h"
35 #include "sceneGraphReducer.h"
37 #include "cullTraverser.h"
38 #include "cullTraverserData.h"
39 #include "geometricBoundingVolume.h"
40 #include "accumulatedAttribs.h"
41 #include "renderState.h"
42 #include "renderModeAttrib.h"
43 #include "decalEffect.h"
47 #include "pStatCollector.h"
48 #include "pStatTimer.h"
49 #include "boundingSphere.h"
55 PStatCollector TextNode::_text_generate_pcollector(
"*:Generate Text");
63 TextNode(
const string &name) :
PandaNode(name) {
68 _usage_hint = GeomEnums::UH_static;
71 _flatten_flags |= FF_strong;
73 if (text_dynamic_merge) {
74 _flatten_flags |= FF_dynamic_merge;
77 if (text_small_caps) {
81 _frame_color.set(1.0f, 1.0f, 1.0f, 1.0f);
82 _card_color.set(1.0f, 1.0f, 1.0f, 1.0f);
86 _frame_ul.set(0.0f, 0.0f);
87 _frame_lr.set(0.0f, 0.0f);
88 _card_ul.set(0.0f, 0.0f);
89 _card_lr.set(0.0f, 0.0f);
92 _coordinate_system = CS_default;
94 _ul3d.set(0.0f, 0.0f, 0.0f);
95 _lr3d.set(0.0f, 0.0f, 0.0f);
111 _usage_hint = GeomEnums::UH_static;
113 _frame_color.set(1.0f, 1.0f, 1.0f, 1.0f);
114 _card_color.set(1.0f, 1.0f, 1.0f, 1.0f);
118 _frame_ul.set(0.0f, 0.0f);
119 _frame_lr.set(0.0f, 0.0f);
120 _card_ul.set(0.0f, 0.0f);
121 _card_lr.set(0.0f, 0.0f);
124 _coordinate_system = CS_default;
126 _ul3d.set(0.0f, 0.0f, 0.0f);
127 _lr3d.set(0.0f, 0.0f, 0.0f);
140 _card_texture(copy._card_texture),
141 _frame_color(copy._frame_color),
142 _card_color(copy._card_color),
144 _max_rows(copy._max_rows),
146 _frame_width(copy._frame_width),
147 _card_border_size(copy._card_border_size),
148 _card_border_uv_portion(copy._card_border_uv_portion),
149 _frame_ul(copy._frame_ul),
150 _frame_lr(copy._frame_lr),
151 _card_ul(copy._card_ul),
152 _card_lr(copy._card_lr),
153 _transform(copy._transform),
154 _coordinate_system(copy._coordinate_system),
158 invalidate_with_measure();
292 PN_stdfloat width = 0.0f;
294 wstring::const_iterator si;
295 for (si = line.begin(); si != line.end(); ++si) {
308 output(ostream &out)
const {
309 PandaNode::output(out);
313 if (_internal_geom != (
PandaNode *)NULL) {
314 geom_count = count_geoms(_internal_geom);
317 out <<
" (" << geom_count <<
" geoms)";
326 write(ostream &out,
int indent_level)
const {
327 PandaNode::write(out, indent_level);
328 TextProperties::write(out, indent_level + 2);
329 indent(out, indent_level + 2)
330 <<
"transform is: " << *TransformState::make_mat(_transform) <<
"\n";
331 indent(out, indent_level + 2)
332 <<
"in coordinate system " << _coordinate_system <<
"\n";
333 indent(out, indent_level + 2)
334 <<
"text is " <<
get_text() <<
"\n";
347 if (text_cat.is_debug()) {
349 <<
"Rebuilding " << get_type() <<
" " << get_name()
350 <<
" with '" << get_text() <<
"'\n";
363 _ul3d.set(0.0f, 0.0f, 0.0f);
364 _lr3d.set(0.0f, 0.0f, 0.0f);
367 string name = get_text();
368 size_t newline = name.find(
'\n');
369 if (newline != string::npos) {
370 name = name.substr(0, newline);
390 CPT(TransformState) transform = TransformState::make_mat(mat);
391 root->set_transform(transform);
393 wstring wtext = get_wtext();
397 assembler.set_properties(*this);
398 assembler.set_max_rows(_max_rows);
399 assembler.set_usage_hint(_usage_hint);
400 assembler.set_dynamic_merge((_flatten_flags & FF_dynamic_merge) != 0);
401 bool all_set = assembler.set_wtext(wtext);
404 _flags &= ~F_has_overflow;
407 _flags |= F_has_overflow;
410 PT(
PandaNode) text_root = assembler.assemble_text();
411 _text_ul = assembler.get_ul();
412 _text_lr = assembler.get_lr();
413 _num_rows = assembler.get_num_rows();
414 _wordwrapped_wtext = assembler.get_wordwrapped_wtext();
418 root->add_child(text, get_draw_order() + 2);
419 text->add_child(text_root);
423 const
LVector2 &ul = assembler.get_ul();
424 const
LVector2 &lr = assembler.get_lr();
425 _ul3d.set(ul[0], 0.0f, ul[1]);
426 _lr3d.set(lr[0], 0.0f, lr[1]);
428 _ul3d = _ul3d * _transform;
429 _lr3d = _lr3d * _transform;
432 _flags &= ~F_needs_measure;
438 if (_flatten_flags & FF_strong) {
440 }
else if (_flatten_flags & FF_medium) {
441 root_np.flatten_medium();
442 }
else if (_flatten_flags & FF_light) {
443 root_np.flatten_light();
450 if (has_card_border()) {
451 card_root = make_card_with_border();
453 card_root = make_card();
455 card_root->set_transform(transform);
456 card_root->set_attrib(ColorAttrib::make_flat(get_card_color()));
457 if (get_card_color()[3] != 1.0f) {
458 card_root->set_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
460 if (has_card_texture()) {
461 card_root->set_attrib(TextureAttrib::make(get_card_texture()));
465 card_root->set_attrib(CullBinAttrib::make(get_bin(), get_draw_order()));
474 card_root->add_child(root);
477 if (get_card_decal()) {
478 card_root->set_effect(DecalEffect::make());
484 frame_root->set_transform(transform);
485 root->add_child(frame_root, get_draw_order() + 1);
486 frame_root->set_attrib(
ColorAttrib::make_flat(get_frame_color()));
487 if (get_frame_color()[3] != 1.0f) {
488 frame_root->set_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
492 frame_root->set_attrib(CullBinAttrib::make(get_bin(), get_draw_order() + 1));
519 <<
"TextNode::get_internal_geom() called.\n";
521 return _internal_geom;
541 SceneGraphReducer::TT_tex_matrix |
542 SceneGraphReducer::TT_other;
560 if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
561 const LMatrix4 &mat = attribs._transform->get_mat();
564 if ((_flags & F_needs_measure) == 0) {
572 if ((attrib_types & SceneGraphReducer::TT_color) != 0) {
584 if ((attrib_types & SceneGraphReducer::TT_color_scale) != 0) {
585 if (attribs._color_scale != (
const RenderAttrib *)NULL) {
588 if (s !=
LVecBase4(1.0f, 1.0f, 1.0f, 1.0f)) {
600 set_shadow_color(sc);
619 if ((_flags & F_needs_rebuild) == 0 &&
622 gr.
apply_attribs(_internal_geom, attribs, attrib_types, transformer);
643 calc_tight_bounds(
LPoint3 &min_point,
LPoint3 &max_point,
bool &found_any,
644 const TransformState *transform,
Thread *current_thread)
const {
645 CPT(TransformState) next_transform =
646 PandaNode::calc_tight_bounds(min_point, max_point, found_any, transform,
651 if (_internal_geom != (
PandaNode *)NULL) {
652 _internal_geom->calc_tight_bounds(min_point, max_point,
653 found_any, next_transform, current_thread);
656 return next_transform;
687 if (_internal_geom != (
PandaNode *)NULL) {
722 int &internal_vertices,
724 Thread *current_thread)
const {
736 vertices[0].set(_ul3d[0], _ul3d[1], _ul3d[2]);
737 vertices[1].set(_ul3d[0], _ul3d[1], _lr3d[2]);
738 vertices[2].set(_ul3d[0], _lr3d[1], _ul3d[2]);
739 vertices[3].set(_ul3d[0], _lr3d[1], _lr3d[2]);
740 vertices[4].set(_lr3d[0], _ul3d[1], _ul3d[2]);
741 vertices[5].set(_lr3d[0], _ul3d[1], _lr3d[2]);
742 vertices[6].set(_lr3d[0], _lr3d[1], _ul3d[2]);
743 vertices[7].set(_lr3d[0], _lr3d[1], _lr3d[2]);
745 gbv->
around(vertices, vertices + 8);
747 internal_bounds = bound;
748 internal_vertices = 0;
766 CPT(
RenderState) child_state = node_state->compose(child->get_state());
781 _flags &= ~(F_needs_rebuild | F_needs_measure);
782 _internal_geom = generate();
808 LVector4 dimensions = get_frame_actual();
809 PN_stdfloat left = dimensions[0];
810 PN_stdfloat right = dimensions[1];
811 PN_stdfloat bottom = dimensions[2];
812 PN_stdfloat top = dimensions[3];
818 ("text", GeomVertexFormat::get_v3(), get_usage_hint());
821 vertex.add_data3(left, 0.0f, top);
822 vertex.add_data3(left, 0.0f, bottom);
823 vertex.add_data3(right, 0.0f, bottom);
824 vertex.add_data3(right, 0.0f, top);
827 frame->add_consecutive_vertices(0, 4);
828 frame->add_vertex(0);
829 frame->close_primitive();
832 geom->add_primitive(frame);
833 frame_node->add_geom(geom, state);
835 if (get_frame_corners()) {
837 corners->add_consecutive_vertices(0, 4);
839 geom2->add_primitive(corners);
840 frame_node->add_geom(geom2, state);
843 return frame_node.p();
855 LVector4 dimensions = get_card_actual();
856 PN_stdfloat left = dimensions[0];
857 PN_stdfloat right = dimensions[1];
858 PN_stdfloat bottom = dimensions[2];
859 PN_stdfloat top = dimensions[3];
862 ("text", GeomVertexFormat::get_v3t2(), get_usage_hint());
866 vertex.add_data3(left, 0.0f, top);
867 vertex.add_data3(left, 0.0f, bottom);
868 vertex.add_data3(right, 0.0f, top);
869 vertex.add_data3(right, 0.0f, bottom);
871 texcoord.add_data2(0.0f, 1.0f);
872 texcoord.add_data2(0.0f, 0.0f);
873 texcoord.add_data2(1.0f, 1.0f);
874 texcoord.add_data2(1.0f, 0.0f);
877 card->add_consecutive_vertices(0, 4);
878 card->close_primitive();
881 geom->add_primitive(card);
883 card_node->add_geom(geom);
885 return card_node.p();
896 make_card_with_border() {
899 LVector4 dimensions = get_card_actual();
900 PN_stdfloat left = dimensions[0];
901 PN_stdfloat right = dimensions[1];
902 PN_stdfloat bottom = dimensions[2];
903 PN_stdfloat top = dimensions[3];
915 ("text", GeomVertexFormat::get_v3t2(), get_usage_hint());
920 vertex.add_data3(left, 0.02, top);
921 vertex.add_data3(left, 0.02, top - _card_border_size);
922 vertex.add_data3(left + _card_border_size, 0.02, top);
923 vertex.add_data3(left + _card_border_size, 0.02,
924 top - _card_border_size);
926 vertex.add_data3(right - _card_border_size, 0.02, top);
927 vertex.add_data3(right - _card_border_size, 0.02,
928 top - _card_border_size);
929 vertex.add_data3(right, 0.02, top);
930 vertex.add_data3(right, 0.02, top - _card_border_size);
932 vertex.add_data3(left, 0.02, bottom + _card_border_size);
933 vertex.add_data3(left, 0.02, bottom);
934 vertex.add_data3(left + _card_border_size, 0.02,
935 bottom + _card_border_size);
936 vertex.add_data3(left + _card_border_size, 0.02, bottom);
938 vertex.add_data3(right - _card_border_size, 0.02,
939 bottom + _card_border_size);
940 vertex.add_data3(right - _card_border_size, 0.02, bottom);
941 vertex.add_data3(right, 0.02, bottom + _card_border_size);
942 vertex.add_data3(right, 0.02, bottom);
944 texcoord.add_data2(0.0f, 1.0f);
945 texcoord.add_data2(0.0f, 1.0f - _card_border_uv_portion);
946 texcoord.add_data2(0.0f + _card_border_uv_portion, 1.0f);
947 texcoord.add_data2(0.0f + _card_border_uv_portion,
948 1.0f - _card_border_uv_portion);
949 texcoord.add_data2(1.0f -_card_border_uv_portion, 1.0f);
950 texcoord.add_data2(1.0f -_card_border_uv_portion,
951 1.0f - _card_border_uv_portion);
952 texcoord.add_data2(1.0f, 1.0f);
953 texcoord.add_data2(1.0f, 1.0f - _card_border_uv_portion);
955 texcoord.add_data2(0.0f, _card_border_uv_portion);
956 texcoord.add_data2(0.0f, 0.0f);
957 texcoord.add_data2(_card_border_uv_portion, _card_border_uv_portion);
958 texcoord.add_data2(_card_border_uv_portion, 0.0f);
960 texcoord.add_data2(1.0f - _card_border_uv_portion, _card_border_uv_portion);
961 texcoord.add_data2(1.0f - _card_border_uv_portion, 0.0f);
962 texcoord.add_data2(1.0f, _card_border_uv_portion);
963 texcoord.add_data2(1.0f, 0.0f);
968 card->add_consecutive_vertices(0, 8);
969 card->close_primitive();
975 card->add_vertex(10);
977 card->add_vertex(12);
979 card->add_vertex(14);
980 card->close_primitive();
983 card->add_consecutive_vertices(8, 8);
984 card->close_primitive();
987 geom->add_primitive(card);
989 card_node->add_geom(geom);
991 return card_node.p();
1005 if (node->is_geom_node()) {
1010 Children children = node->get_children();
1011 for (
int i = 0; i < children.get_num_children(); ++i) {
1012 num_geoms += count_geoms(children.get_child(i));
static const LMatrix4f & ident_mat()
Returns an identity matrix.
A basic node of the scene graph or data graph.
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
virtual int get_unsafe_to_apply_attribs() const
Returns the union of all attributes from SceneGraphReducer::AttribTypes that may not safely be applie...
This is the base class for a number of render attributes (other than transform) that may be set on sc...
static bool has_character(wchar_t character, const TextProperties &properties)
Returns true if the named character exists in the font or can be synthesized by Panda, false otherwise.
Defines a series of disconnected points.
This class can be used to convert text between multiple representations, e.g.
This defines a bounding sphere, consisting of a center and a radius.
An interface for simplifying ("flattening") scene graphs by eliminating unneeded nodes and collapsing...
string get_text() const
Returns the current text, as encoded via the current encoding system.
This collects together the pieces of data that are accumulated for each node while walking the scene ...
Defines a series of triangle strips.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
static bool is_whitespace(wchar_t character, const TextProperties &properties)
Returns true if the indicated character represents whitespace in the font, or false if anything visib...
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
Type get_color_type() const
Returns the type of color specified by this ColorAttrib.
static const LMatrix4f & convert_mat(CoordinateSystem from, CoordinateSystem to)
Returns a matrix that transforms from the indicated coordinate system to the indicated coordinate sys...
virtual void r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state, GeomTransformer &transformer, Thread *current_thread)
The recursive implementation of prepare_scene().
void traverse(const NodePath &root)
Begins the traversal from the indicated node.
An encapsulation of a font; i.e.
virtual void apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, GeomTransformer &transformer)
Applies whatever attributes are specified in the AccumulatedAttribs object (and by the attrib_types b...
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
bool is_whitespace(wchar_t character) const
Returns true if the indicated character represents whitespace in the font, or false if anything visib...
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data)
This function will be called during the cull traversal to perform any additional operations that shou...
A lightweight class that represents a single element that may be timed and/or counted via stats...
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
static bool has_exact_character(wchar_t character, const TextProperties &properties)
Returns true if the named character exists in the font exactly as named, false otherwise.
bool has_exact_character(wchar_t character) const
Returns true if the named character exists in the font exactly as named, false otherwise.
static PN_stdfloat calc_width(wchar_t character, const TextProperties &properties)
Returns the width of a single character, according to its associated font.
This class is used by the SceneGraphReducer to maintain and accumulate the set of attributes we have ...
const LColor & get_color() const
If the type is T_flat or T_off, this returns the color that will be applied to geometry.
This is a 4-by-4 transform matrix.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
const LVecBase4 & get_scale() const
Returns the scale to be applied to colors.
A container for geometry primitives.
This class is not normally used directly by user code, but is used by the TextNode to lay out a block...
virtual bool is_renderable() const
Returns true if there is some value to visiting this particular node during the cull traversal for an...
This is a four-component vector distance.
bool has_character(wchar_t character) const
Returns true if the named character exists in the font or can be synthesized by Panda, false otherwise.
Applies a scale to colors in the scene graph and on vertices.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
This is the base class for all three-component vectors and points.
TextFont * get_font() const
Returns the font currently in use, if any.
void apply_attribs(PandaNode *node, int attrib_types=~(TT_clip_plane|TT_cull_face|TT_apply_texture_color))
Walks the scene graph, accumulating attribs of the indicated types, applying them to the vertices...
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
int flatten_strong()
The strongest possible flattening.
This is a two-component vector offset.
A thread; that is, a lightweight process.
PN_stdfloat calc_width(wchar_t character) const
Returns the width of a single character of the font, or 0.0 if the character is not known...
Defines a series of line strips.
The primary interface to this module.
This defines the set of visual properties that may be assigned to the individual characters of the te...
Specifies how polygons are to be drawn.
Indicates what color should be applied to renderable geometry.
virtual void r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state, GeomTransformer &transformer, Thread *current_thread)
The recursive implementation of prepare_scene().
TypeHandle is the identifier used to differentiate C++ class types.
PandaNode * get_internal_geom() const
Returns the actual node that is used internally to render the text, if the TextNode is parented withi...
virtual void compute_internal_bounds(CPT(BoundingVolume)&internal_bounds, int &internal_vertices, int pipeline_stage, Thread *current_thread) const
Called when needed to recompute the node's _internal_bound object.
bool around(const GeometricBoundingVolume **first, const GeometricBoundingVolume **last)
Resets the volume to enclose only the volumes indicated.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
A node that holds Geom objects, renderable pieces of geometry.
int get_num_geoms() const
Returns the number of geoms in the node.