Panda3D
textProperties.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file textProperties.cxx
10  * @author drose
11  * @date 2004-04-06
12  */
13 
14 #include "textProperties.h"
15 #include "config_text.h"
16 #include "default_font.h"
17 #include "dynamicTextFont.h"
18 #include "staticTextFont.h"
19 #include "bamFile.h"
20 #include "fontPool.h"
21 #include "colorAttrib.h"
22 #include "cullBinAttrib.h"
23 #include "transparencyAttrib.h"
24 
25 PT(TextFont) TextProperties::_default_font;
26 bool TextProperties::_loaded_default_font = false;
27 
28 TypeHandle TextProperties::_type_handle;
29 
30 /**
31  *
32  */
33 TextProperties::
34 TextProperties() :
35  _specified(0),
36 
37  _small_caps(text_small_caps),
38  _small_caps_scale(text_small_caps_scale),
39  _slant(0.0f),
40  _underscore(false),
41  _underscore_height(0.0f),
42  _align(A_left),
43  _indent_width(0.0f),
44  _wordwrap_width(0.0f),
45  _preserve_trailing_whitespace(false),
46  _text_color(1.0f, 1.0f, 1.0f, 1.0f),
47  _shadow_color(0.0f, 0.0f, 0.0f, 1.0f),
48  _shadow_offset(0.0f, 0.0f),
49  _draw_order(1),
50  _tab_width(text_tab_width),
51  _glyph_scale(1.0f),
52  _glyph_shift(0.0f),
53  _text_scale(1.0f),
54  _direction(D_rtl) {
55 }
56 
57 /**
58  *
59  */
60 TextProperties::
61 TextProperties(const TextProperties &copy) {
62  (*this) = copy;
63  _text_state = copy._text_state;
64  _shadow_state = copy._shadow_state;
65 }
66 
67 /**
68  *
69  */
70 void TextProperties::
71 operator = (const TextProperties &copy) {
72  _specified = copy._specified;
73 
74  _font = copy._font;
75  _small_caps = copy._small_caps;
76  _small_caps_scale = copy._small_caps_scale;
77  _slant = copy._slant;
78  _underscore = copy._underscore;
79  _underscore_height = copy._underscore_height;
80  _align = copy._align;
81  _indent_width = copy._indent_width;
82  _wordwrap_width = copy._wordwrap_width;
83  _preserve_trailing_whitespace = copy._preserve_trailing_whitespace;
84  _text_color = copy._text_color;
85  _shadow_color = copy._shadow_color;
86  _shadow_offset = copy._shadow_offset;
87  _bin = copy._bin;
88  _draw_order = copy._draw_order;
89  _tab_width = copy._tab_width;
90  _glyph_scale = copy._glyph_scale;
91  _glyph_shift = copy._glyph_shift;
92  _text_scale = copy._text_scale;
93  _direction = copy._direction;
94 
95  _text_state.clear();
96  _shadow_state.clear();
97 }
98 
99 /**
100  *
101  */
102 bool TextProperties::
103 operator == (const TextProperties &other) const {
104  if (_specified != other._specified) {
105  return false;
106  }
107 
108  if ((_specified & F_has_font) && _font != other._font) {
109  return false;
110  }
111  if ((_specified & F_has_small_caps) && _small_caps != other._small_caps) {
112  return false;
113  }
114  if ((_specified & F_has_small_caps_scale) && _small_caps_scale != other._small_caps_scale) {
115  return false;
116  }
117  if ((_specified & F_has_slant) && _slant != other._slant) {
118  return false;
119  }
120  if ((_specified & F_has_underscore) && _underscore != other._underscore) {
121  return false;
122  }
123  if ((_specified & F_has_underscore_height) && _underscore_height != other._underscore_height) {
124  return false;
125  }
126  if ((_specified & F_has_align) && _align != other._align) {
127  return false;
128  }
129  if ((_specified & F_has_indent) && _indent_width != other._indent_width) {
130  return false;
131  }
132  if ((_specified & F_has_wordwrap) && _wordwrap_width != other._wordwrap_width) {
133  return false;
134  }
135  if ((_specified & F_has_preserve_trailing_whitespace) && _preserve_trailing_whitespace != other._preserve_trailing_whitespace) {
136  return false;
137  }
138  if ((_specified & F_has_text_color) && _text_color != other._text_color) {
139  return false;
140  }
141  if ((_specified & F_has_text_color) && _text_color != other._text_color) {
142  return false;
143  }
144  if ((_specified & F_has_shadow_color) && _shadow_color != other._shadow_color) {
145  return false;
146  }
147  if ((_specified & F_has_shadow) && _shadow_offset != other._shadow_offset) {
148  return false;
149  }
150  if ((_specified & F_has_bin) && _bin != other._bin) {
151  return false;
152  }
153  if ((_specified & F_has_draw_order) && _draw_order != other._draw_order) {
154  return false;
155  }
156  if ((_specified & F_has_tab_width) && _tab_width != other._tab_width) {
157  return false;
158  }
159  if ((_specified & F_has_glyph_scale) && _glyph_scale != other._glyph_scale) {
160  return false;
161  }
162  if ((_specified & F_has_glyph_shift) && _glyph_shift != other._glyph_shift) {
163  return false;
164  }
165  if ((_specified & F_has_text_scale) && _text_scale != other._text_scale) {
166  return false;
167  }
168  if ((_specified & F_has_direction) && _direction != other._direction) {
169  return false;
170  }
171  return true;
172 }
173 
174 /**
175  * Unsets all properties that have been specified so far, and resets the
176  * TextProperties structure to its initial empty state.
177  */
178 void TextProperties::
179 clear() {
180  (*this) = TextProperties();
181 }
182 
183 /**
184  * Sets any properties that are explicitly specified in other on this object.
185  * Leaves other properties unchanged.
186  */
187 void TextProperties::
189  if (other.has_font()) {
190  set_font(other.get_font());
191  }
192  if (other.has_small_caps()) {
195  }
196  if (other.has_slant()) {
197  set_slant(other.get_slant());
198  }
199  if (other.has_underscore()) {
201  }
202  if (other.has_underscore_height()) {
204  }
205  if (other.has_align()) {
206  set_align(other.get_align());
207  }
208  if (other.has_indent()) {
209  set_indent(other.get_indent());
210  }
211  if (other.has_wordwrap()) {
212  set_wordwrap(other.get_wordwrap());
213  }
214  if (other.has_text_color()) {
215  set_text_color(other.get_text_color());
216  }
217  if (other.has_shadow_color()) {
218  set_shadow_color(other.get_shadow_color());
219  }
220  if (other.has_shadow()) {
221  set_shadow(other.get_shadow());
222  }
223  if (other.has_bin()) {
224  set_bin(other.get_bin());
225  }
226  if (other.has_draw_order()) {
228  }
229  if (other.has_tab_width()) {
230  set_tab_width(other.get_tab_width());
231  }
232 
233  // The glyph scale and shift are a special case: rather than replacing the
234  // previous value, they modify it, so that they apply cumulatively to nested
235  // TextProperties.
236  if (other.has_glyph_shift()) {
238  }
239  if (other.has_glyph_scale()) {
241  }
242 
243  if (other.has_text_scale()) {
245  }
246  if (other.has_direction()) {
247  set_direction(other.get_direction());
248  }
249 }
250 
251 
252 /**
253  *
254  */
255 void TextProperties::
256 write(std::ostream &out, int indent_level) const {
257  if (!is_any_specified()) {
258  indent(out, indent_level)
259  << "default properties\n";
260  }
261  if (has_font()) {
262  if (get_font() != nullptr) {
263  indent(out, indent_level)
264  << "with font " << _font->get_name() << "\n";
265  } else {
266  indent(out, indent_level)
267  << "with NULL font\n";
268  }
269  }
270  if (has_small_caps()) {
271  indent(out, indent_level)
272  << "small caps = " << get_small_caps() << "\n";
273  }
274  if (has_small_caps_scale()) {
275  indent(out, indent_level)
276  << "small caps scale = " << get_small_caps_scale() << "\n";
277  }
278  if (has_slant()) {
279  indent(out, indent_level)
280  << "slant = " << get_slant() << "\n";
281  }
282  if (has_underscore()) {
283  indent(out, indent_level)
284  << "underscore = " << get_underscore() << "\n";
285  }
286  if (has_underscore_height()) {
287  indent(out, indent_level)
288  << "underscore_height = " << get_underscore_height() << "\n";
289  }
290 
291  if (has_align()) {
292  indent(out, indent_level)
293  << "alignment is ";
294  switch (get_align()) {
295  case A_left:
296  out << "A_left\n";
297  break;
298 
299  case A_right:
300  out << "A_right\n";
301  break;
302 
303  case A_center:
304  out << "A_center\n";
305  break;
306 
307  case A_boxed_left:
308  out << "A_boxed_left\n";
309  break;
310 
311  case A_boxed_right:
312  out << "A_boxed_right\n";
313  break;
314 
315  case A_boxed_center:
316  out << "A_boxed_center\n";
317  break;
318  }
319  }
320 
321  if (has_indent()) {
322  indent(out, indent_level)
323  << "indent at " << get_indent() << " units.\n";
324  }
325 
326  if (has_wordwrap()) {
327  indent(out, indent_level)
328  << "word-wrapping at " << get_wordwrap() << " units.\n";
329  }
330 
331  if (has_text_color()) {
332  indent(out, indent_level)
333  << "text color is " << get_text_color() << "\n";
334  }
335 
336  if (has_shadow()) {
337  indent(out, indent_level)
338  << "shadow at " << get_shadow() << "\n";
339  }
340  if (has_shadow_color()) {
341  indent(out, indent_level)
342  << "shadow color is " << get_shadow_color() << "\n";
343  }
344 
345  if (has_bin()) {
346  indent(out, indent_level)
347  << "bin is " << get_bin() << "\n";
348  }
349  if (has_draw_order()) {
350  indent(out, indent_level)
351  << "draw order is " << get_draw_order() << "\n";
352  }
353 
354  if (has_tab_width()) {
355  indent(out, indent_level)
356  << "tab width is " << get_tab_width() << "\n";
357  }
358 
359  if (has_glyph_scale()) {
360  indent(out, indent_level)
361  << "glyph scale is " << get_glyph_scale() << "\n";
362  }
363  if (has_glyph_shift()) {
364  indent(out, indent_level)
365  << "glyph shift is " << get_glyph_shift() << "\n";
366  }
367 
368  if (has_text_scale()) {
369  indent(out, indent_level)
370  << "text scale is " << get_text_scale() << "\n";
371  }
372 
373  if (has_direction()) {
374  indent(out, indent_level)
375  << "direction is ";
376  switch (get_direction()) {
377  case D_ltr:
378  out << "D_ltr\n";
379  break;
380 
381  case D_rtl:
382  out << "D_rtl\n";
383  break;
384  }
385  }
386 }
387 
388 /**
389  * Returns a RenderState object suitable for rendering text with these
390  * properties.
391  */
393 get_text_state() const {
394  if (!_text_state.is_null()) {
395  return _text_state;
396  }
397 
398  CPT(RenderState) state = RenderState::make_empty();
399 
400  if (has_text_color()) {
401  state = state->add_attrib(ColorAttrib::make_flat(get_text_color()));
402  if (get_text_color()[3] != 1.0) {
403  state = state->add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
404  }
405  }
406 
407  if (has_bin()) {
408  state = state->add_attrib(CullBinAttrib::make(get_bin(), get_draw_order() + 2));
409  }
410 
411  std::swap(_text_state, state);
412  return _text_state;
413 }
414 
415 /**
416  * Returns a RenderState object suitable for rendering the shadow of this text
417  * with these properties.
418  */
421  if (!_shadow_state.is_null()) {
422  return _shadow_state;
423  }
424 
425  CPT(RenderState) state = RenderState::make_empty();
426 
427  state = state->add_attrib(ColorAttrib::make_flat(get_shadow_color()));
428  if (get_shadow_color()[3] != 1.0) {
429  state = state->add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
430  }
431 
432  if (has_bin()) {
433  state = state->add_attrib(CullBinAttrib::make(get_bin(), get_draw_order() + 1));
434  }
435 
436  std::swap(_shadow_state, state);
437  return _shadow_state;
438 }
439 
440 /**
441  * This function is called once (or never), the first time someone attempts to
442  * render a TextNode using the default font. It should attempt to load the
443  * default font, using the compiled-in version if it is available, or whatever
444  * system file may be named in Configrc.
445  */
446 void TextProperties::
447 load_default_font() {
448  _loaded_default_font = true;
449 
450  if (!text_default_font.empty()) {
451  // First, attempt to load the user-specified filename.
452  _default_font = FontPool::load_font(text_default_font.get_value());
453  if (_default_font != nullptr && _default_font->is_valid()) {
454  return;
455  }
456  }
457 
458  // Then, attempt to load the compiled-in font, if we have one.
459 #ifdef COMPILE_IN_DEFAULT_FONT
460 #ifdef HAVE_FREETYPE
461  // Loading the compiled-in FreeType font is relatively easy.
462  _default_font = new DynamicTextFont((const char *)default_font_data,
463  default_font_size, 0);
464  // The compiled-in font seems to confuse FreeType about its winding order.
465  ((DynamicTextFont *)_default_font.p())->set_winding_order(DynamicTextFont::WO_left);
466 
467 #else
468  // The compiled-in Bam font requires creating a BamFile object to decode it.
469  std::string data((const char *)default_font_data, default_font_size);
470 
471 #ifdef HAVE_ZLIB
472  // The font data is stored compressed; decompress it on-the-fly.
473  std::istringstream inz(data);
474  IDecompressStream in(&inz, false);
475 
476 #else
477  // The font data is stored uncompressed, so just load it.
478  std::istringstream in(data);
479 #endif // HAVE_ZLIB
480 
481  BamFile bam_file;
482  if (bam_file.open_read(in, "default font stream")) {
483  PT(PandaNode) node = bam_file.read_node();
484  if (node != nullptr) {
485  _default_font = new StaticTextFont(node);
486  }
487  }
488 
489 #endif // HAVE_FREETYPE
490 #endif // COMPILE_IN_DEFAULT_FONT
491 }
bool is_any_specified() const
Returns true if any properties have been specified, false otherwise.
The principle public interface to reading and writing Bam disk files.
Definition: bamFile.h:41
set_align
Specifies the alignment of the text within its margins.
get_small_caps_scale
Returns the scale factor applied to lowercase letters from their uppercase equivalents,...
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
get_font
Returns the font currently in use, if any.
bool open_read(const Filename &bam_filename, bool report_errors=true)
Attempts to open the indicated filename for reading.
Definition: bamFile.cxx:51
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const RenderState * get_text_state() const
Returns a RenderState object suitable for rendering text with these properties.
set_direction
Specifies the text direction.
set_text_scale
Specifies the factor by which to scale the text, in addition to any scalings imposed by the node,...
void add_properties(const TextProperties &other)
Sets any properties that are explicitly specified in other on this object.
set_glyph_scale
Specifies the factor by which to scale each letter of the text as it is placed, in addition to any sc...
get_direction
Returns the direction of the text as specified by set_direction().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_shadow
Returns the offset of the shadow as set by set_shadow().
get_draw_order
Returns the drawing order set with set_draw_order().
get_underscore
Returns the underscore flag.
set_underscore_height
Specifies the vertical height of the underscore, relative to the text baseline.
get_tab_width
Returns the width set via set_tab_width().
get_slant
Returns the factor by which the text is specified to slant to the right.
An encapsulation of a font; i.e.
Definition: textFont.h:32
get_glyph_scale
Returns the scale factor of each letter as specified by set_glyph_scale().
set_tab_width
Sets the width of each tab stop, in screen units.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A StaticTextFont is loaded up from a model that was previously generated via egg-mkfont,...
has_bin
Returns true if an explicit drawing bin has been set via set_bin(), false otherwise.
set_shadow
Specifies that the text should be drawn with a shadow, by creating a second copy of the text and offs...
get_value
Returns the variable's value.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
set_draw_order
Sets the drawing order of text created by the TextNode.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
set_small_caps
Sets the small_caps flag.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
set_wordwrap
Sets the text up to automatically wordwrap when it exceeds the indicated width.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_bin
Returns the drawing bin set with set_bin(), or empty string if no bin has been set.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
set_glyph_shift
Specifies a vertical amount to shift each letter of the text as it is placed.
set_slant
Specifies the factor by which the text slants to the right.
void clear()
Unsets all properties that have been specified so far, and resets the TextProperties structure to its...
set_indent
Specifies the amount of extra space that is inserted before the first character of each line.
static TextFont * load_font(const std::string &filename)
Loads the given filename up into a font, if it has not already been loaded, and returns the new font.
Definition: fontPool.I:40
set_bin
Names the CullBin that the text geometry should be assigned to.
This defines the set of visual properties that may be assigned to the individual characters of the te...
get_underscore_height
Returns the vertical height of the underscore; see set_underscore_height().
set_underscore
Sets the underscore flag.
set_small_caps_scale
Sets the scale factor applied to lowercase letters from their uppercase equivalents,...
set_font
Sets the font that will be used when making text.
get_glyph_shift
Returns the vertical shift of each letter as specified by set_glyph_shift().
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
get_text_scale
Returns the scale factor of the text as specified by set_text_scale().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const RenderState * get_shadow_state() const
Returns a RenderState object suitable for rendering the shadow of this text with these properties.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_small_caps
Returns the small_caps flag.