From 993b7f7cfc5955e8821cbebae08e9bd2d9961fc8 Mon Sep 17 00:00:00 2001 From: David Rose Date: Wed, 3 Jan 2001 21:33:17 +0000 Subject: [PATCH] *** empty log message *** --- panda/src/text/textNode.I | 80 +++++++++++++++--------- panda/src/text/textNode.cxx | 117 +++++++++++++++++++++++++++++++++++- panda/src/text/textNode.h | 8 ++- 3 files changed, 173 insertions(+), 32 deletions(-) diff --git a/panda/src/text/textNode.I b/panda/src/text/textNode.I index f7789ad39d..d97014ecd6 100644 --- a/panda/src/text/textNode.I +++ b/panda/src/text/textNode.I @@ -86,7 +86,7 @@ set_font(Node *font_def) { _font_height = 1.0; find_characters(font_def); - rebuild(); + rebuild(true); } //////////////////////////////////////////////////////////////////// @@ -118,7 +118,7 @@ get_line_height() const { INLINE void TextNode:: set_slant(float slant) { _slant = slant; - rebuild(); + rebuild(true); } //////////////////////////////////////////////////////////////////// @@ -139,7 +139,7 @@ get_slant() const { INLINE void TextNode:: set_align(int align_type) { _align = align_type; - rebuild(); + rebuild(true); } //////////////////////////////////////////////////////////////////// @@ -162,7 +162,7 @@ INLINE void TextNode:: set_wordwrap(float wordwrap) { _flags |= F_has_wordwrap; _wordwrap_width = wordwrap; - rebuild(); + rebuild(true); } //////////////////////////////////////////////////////////////////// @@ -174,7 +174,7 @@ set_wordwrap(float wordwrap) { INLINE void TextNode:: clear_wordwrap() { _flags &= ~F_has_wordwrap; - rebuild(); + rebuild(true); } //////////////////////////////////////////////////////////////////// @@ -216,7 +216,7 @@ INLINE void TextNode:: set_text_color(const Colorf &text_color) { _text_color = text_color; _flags |= F_has_text_color; - rebuild(); + rebuild(false); } //////////////////////////////////////////////////////////////////// @@ -268,7 +268,7 @@ set_frame_color(float r, float g, float b, float a) { INLINE void TextNode:: set_frame_color(const Colorf &frame_color) { _frame_color = frame_color; - rebuild(); + rebuild(false); } //////////////////////////////////////////////////////////////////// @@ -291,7 +291,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(); + rebuild(false); } //////////////////////////////////////////////////////////////////// @@ -302,7 +302,7 @@ set_card_border(float size, float uv_portion) { INLINE void TextNode:: clear_card_border() { _flags &= ~F_has_card_border; - rebuild(); + rebuild(false); } //////////////////////////////////////////////////////////////////// @@ -353,7 +353,7 @@ set_card_color(float r, float g, float b, float a) { INLINE void TextNode:: set_card_color(const Colorf &card_color) { _card_color = card_color; - rebuild(); + rebuild(false); } //////////////////////////////////////////////////////////////////// @@ -375,7 +375,7 @@ INLINE void TextNode:: set_card_texture(Texture *card_texture) { _flags |= F_has_card_texture; _card_texture = card_texture; - rebuild(); + rebuild(false); } //////////////////////////////////////////////////////////////////// @@ -387,7 +387,7 @@ INLINE void TextNode:: clear_card_texture() { _flags &= ~F_has_card_texture; _card_texture = NULL; - rebuild(); + rebuild(false); } //////////////////////////////////////////////////////////////////// @@ -428,7 +428,7 @@ set_shadow_color(float r, float g, float b, float a) { INLINE void TextNode:: set_shadow_color(const Colorf &shadow_color) { _shadow_color = shadow_color; - rebuild(); + rebuild(false); } //////////////////////////////////////////////////////////////////// @@ -455,7 +455,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(); + rebuild(false); } //////////////////////////////////////////////////////////////////// @@ -474,7 +474,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(); + rebuild(false); } //////////////////////////////////////////////////////////////////// @@ -486,7 +486,7 @@ set_frame_actual(float left, float right, float bottom, float top) { INLINE void TextNode:: clear_frame() { _flags &= ~F_has_frame; - rebuild(); + rebuild(false); } //////////////////////////////////////////////////////////////////// @@ -618,7 +618,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(); + rebuild(false); } //////////////////////////////////////////////////////////////////// @@ -637,7 +637,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(); + rebuild(false); } //////////////////////////////////////////////////////////////////// @@ -649,7 +649,7 @@ set_card_actual(float left, float right, float bottom, float top) { INLINE void TextNode:: clear_card() { _flags &= ~F_has_card; - rebuild(); + rebuild(false); } //////////////////////////////////////////////////////////////////// @@ -746,7 +746,7 @@ INLINE void TextNode:: set_shadow(float xoffset, float yoffset) { _flags |= F_has_shadow; _shadow_offset.set(xoffset, yoffset); - rebuild(); + rebuild(false); } //////////////////////////////////////////////////////////////////// @@ -758,7 +758,7 @@ set_shadow(float xoffset, float yoffset) { INLINE void TextNode:: clear_shadow() { _flags &= ~F_has_shadow; - rebuild(); + rebuild(false); } //////////////////////////////////////////////////////////////////// @@ -795,7 +795,7 @@ get_shadow() const { INLINE void TextNode:: set_draw_order(int draw_order) { _draw_order = draw_order; - rebuild(); + rebuild(false); } //////////////////////////////////////////////////////////////////// @@ -822,7 +822,7 @@ set_billboard(bool billboard) { } else { _flags &= ~F_billboard; } - rebuild(); + rebuild(false); } //////////////////////////////////////////////////////////////////// @@ -844,7 +844,7 @@ get_billboard() const { INLINE void TextNode:: set_transform(const LMatrix4f &transform) { _transform = transform; - rebuild(); + rebuild(true); } //////////////////////////////////////////////////////////////////// @@ -866,7 +866,7 @@ get_transform() const { INLINE void TextNode:: set_coordinate_system(CoordinateSystem coordinate_system) { _coordinate_system = coordinate_system; - rebuild(); + rebuild(true); } //////////////////////////////////////////////////////////////////// @@ -888,7 +888,7 @@ get_coordinate_system() const { INLINE void TextNode:: set_text(const string &text) { _text = text; - rebuild(); + rebuild(true); } //////////////////////////////////////////////////////////////////// @@ -899,7 +899,7 @@ set_text(const string &text) { INLINE void TextNode:: clear_text() { _text = ""; - rebuild(); + rebuild(true); } //////////////////////////////////////////////////////////////////// @@ -926,7 +926,11 @@ get_text() const { // Function: TextNode::rebuild // Access: Public // Description: Updates the TextNode, if it is not frozen, or marks -// the TextNode as requiring an update if it is. +// 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 @@ -934,14 +938,32 @@ get_text() const { // goes wrong. //////////////////////////////////////////////////////////////////// INLINE void TextNode:: -rebuild() { +rebuild(bool needs_measure) { if (_freeze_level <= 0) { do_rebuild(); } else { _needs_rebuild = true; + + if (needs_measure) { + measure(); + } } } +//////////////////////////////////////////////////////////////////// +// Function: TextNode::measure +// Access: Public +// 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: Public diff --git a/panda/src/text/textNode.cxx b/panda/src/text/textNode.cxx index c0fc1d5765..fc385fe80e 100644 --- a/panda/src/text/textNode.cxx +++ b/panda/src/text/textNode.cxx @@ -476,6 +476,44 @@ do_rebuild() { } } +//////////////////////////////////////////////////////////////////// +// Function: TextNode::do_measure +// Access: Private +// Description: Can be called in lieu of do_rebuild() to measure the +// text and set up the bounding boxes properly without +// actually assembling it. +//////////////////////////////////////////////////////////////////// +void TextNode:: +do_measure() { + _ul2d.set(0.0, 0.0); + _lr2d.set(0.0, 0.0); + _ul3d.set(0.0, 0.0, 0.0); + _lr3d.set(0.0, 0.0, 0.0); + _num_rows = 0; + + if (_text.empty() || _defs.empty()) { + return; + } + + string text = _text; + if (has_wordwrap()) { + text = wordwrap_to(text, _wordwrap_width); + } + + LVector2f ul, lr; + int num_rows; + measure_text(text.c_str(), ul, lr, num_rows); + + _num_rows = num_rows; + _ul2d = ul; + _lr2d = lr; + _ul3d.set(ul[0], 0.0, ul[1]); + _lr3d.set(lr[0], 0.0, lr[1]); + + _ul3d = _ul3d * _transform; + _lr3d = _lr3d * _transform; +} + //////////////////////////////////////////////////////////////////// // Function: TextNode::find_character_gsets // Access: Private @@ -628,7 +666,8 @@ assemble_row(const char *&source, Node *dest) { CharDefs::const_iterator cdi = _defs.find(character); if (cdi == _defs.end()) { - nout << "No definition for character " << character << endl; + text_cat.warning() + << "No definition for character " << character << endl; } else { Geom *char_geom = (*cdi).second._geom; @@ -664,7 +703,7 @@ assemble_row(const char *&source, Node *dest) { //////////////////////////////////////////////////////////////////// Node *TextNode:: assemble_text(const char *source, LVector2f &ul, LVector2f &lr, - int &num_rows) { + int &num_rows) { ul.set(0.0, 0.8 * _font_height); lr.set(0.0, 0.0); @@ -722,6 +761,80 @@ assemble_text(const char *source, LVector2f &ul, LVector2f &lr, return root_node; } +//////////////////////////////////////////////////////////////////// +// Function: TextNode::measure_row +// Access: Private +// Description: Returns the length of the row in units, as it would +// be if it were assembled, without actually assembling +// it. +//////////////////////////////////////////////////////////////////// +float TextNode:: +measure_row(const char *&source) { + float xpos = 0.0; + while (*source != '\0' && *source != '\n') { + int character = (unsigned char)*source; + + if (character == ' ') { + // A space is a special case. + xpos += 0.25; + + } else { + // A printable character. + + CharDefs::const_iterator cdi = _defs.find(character); + if (cdi == _defs.end()) { + text_cat.warning() + << "No definition for character " << character << endl; + + } else { + float char_width = (*cdi).second._width; + xpos += char_width; + } + } + source++; + } + + return xpos; +} + +//////////////////////////////////////////////////////////////////// +// Function: TextNode::measure_text +// Access: Private +// Description: Sets the ul, lr corners to fit the text, without +// actually assembling it. +//////////////////////////////////////////////////////////////////// +void TextNode:: +measure_text(const char *source, LVector2f &ul, LVector2f &lr, + int &num_rows) { + ul.set(0.0, 0.8 * _font_height); + lr.set(0.0, 0.0); + + float posy = 0.0; + while (*source != '\0') { + float row_width = measure_row(source); + if (*source != '\0') { + // Skip past the newline. + source++; + } + + if (_align == TM_ALIGN_LEFT) { + lr[0] = max(lr[0], row_width); + + } else if (_align == TM_ALIGN_RIGHT) { + ul[0] = min(ul[0], -row_width); + + } else { + lr[0] = max(lr[0], row_width / 2); + ul[0] = min(ul[0], -row_width / 2); + } + + posy -= _font_height; + num_rows++; + } + + lr[1] = posy + 0.8 * _font_height; +} + //////////////////////////////////////////////////////////////////// // Function: TextNode::make_frame // Access: Private diff --git a/panda/src/text/textNode.h b/panda/src/text/textNode.h index f4f1e51680..df633b0e34 100644 --- a/panda/src/text/textNode.h +++ b/panda/src/text/textNode.h @@ -147,7 +147,8 @@ PUBLISHED: void print() const; void write(ostream &out) const; - INLINE void rebuild(); + 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). @@ -166,12 +167,17 @@ PUBLISHED: private: void do_rebuild(); + void do_measure(); bool find_character_gsets(Node *root, Geom *&ch, GeomPoint *&dot, AllTransitionsWrapper &trans); void find_characters(Node *root); float assemble_row(const char *&source, Node *dest); Node *assemble_text(const char *source, LVector2f &ul, LVector2f &lr, int &num_rows); + float measure_row(const char *&source); + void measure_text(const char *source, LVector2f &ul, LVector2f &lr, + int &num_rows); + Node *make_frame(); Node *make_card(); Node *make_card_with_border();