From 9aeeb1ce1acc580a62a5ecf36a08d3dcd1403130 Mon Sep 17 00:00:00 2001 From: David Rose Date: Thu, 6 Feb 2003 01:32:05 +0000 Subject: [PATCH] more control over encoding --- panda/src/text/textNode.I | 99 +++++++++++++++++++++++++++++++++++-- panda/src/text/textNode.cxx | 84 ++++++++++++++++++++++++------- panda/src/text/textNode.h | 26 +++++++--- 3 files changed, 177 insertions(+), 32 deletions(-) diff --git a/panda/src/text/textNode.I b/panda/src/text/textNode.I index b49009c541..dbb3883930 100644 --- a/panda/src/text/textNode.I +++ b/panda/src/text/textNode.I @@ -154,6 +154,7 @@ get_default_encoding() { return _default_encoding; } +/* //////////////////////////////////////////////////////////////////// // Function: TextNode::set_expand_amp // Access: Published @@ -185,6 +186,7 @@ INLINE bool TextNode:: get_expand_amp() const { return (_flags & F_expand_amp) != 0; } +*/ //////////////////////////////////////////////////////////////////// // Function: TextNode::get_line_height @@ -1129,6 +1131,21 @@ set_text(const string &text) { } } +//////////////////////////////////////////////////////////////////// +// Function: TextNode::set_text +// Access: Published +// Description: The two-parameter version of set_text() accepts an +// explicit encoding; the text is immediately decoded +// and stored as a wide-character string. Subsequent +// calls to get_text() will return the same text +// re-encoded using whichever encoding is specified by +// set_encoding(). +//////////////////////////////////////////////////////////////////// +INLINE void TextNode:: +set_text(const string &text, TextNode::Encoding encoding) { + set_wtext(decode_text(text, encoding)); +} + //////////////////////////////////////////////////////////////////// // Function: TextNode::clear_text // Access: Published @@ -1159,7 +1176,8 @@ has_text() const { //////////////////////////////////////////////////////////////////// // Function: TextNode::get_text // Access: Published -// Description: +// Description: Returns the current text, as encoded via the current +// encoding system. //////////////////////////////////////////////////////////////////// INLINE string TextNode:: get_text() const { @@ -1170,6 +1188,17 @@ get_text() const { return _text; } +//////////////////////////////////////////////////////////////////// +// Function: TextNode::get_text +// Access: Published +// Description: Returns the current text, as encoded via the indicated +// encoding system. +//////////////////////////////////////////////////////////////////// +INLINE string TextNode:: +get_text(TextNode::Encoding encoding) const { + return encode_wtext(get_wtext(), encoding); +} + //////////////////////////////////////////////////////////////////// // Function: TextNode::append_text // Access: Published @@ -1184,14 +1213,14 @@ append_text(const string &text) { } //////////////////////////////////////////////////////////////////// -// Function: TextNode::append_char +// Function: TextNode::append_unicode_char // Access: Published // Description: Appends a single character to the end of the stored // text. This may be a wide character, up to 16 bits in // Unicode. //////////////////////////////////////////////////////////////////// INLINE void TextNode:: -append_char(int character) { +append_unicode_char(int character) { _wtext = get_wtext() + wstring(1, (wchar_t)character); _flags = (_flags | F_got_wtext) & ~F_got_text; invalidate_with_measure(); @@ -1210,7 +1239,7 @@ get_num_chars() const { } //////////////////////////////////////////////////////////////////// -// Function: TextNode::get_char +// Function: TextNode::get_unicode_char // Access: Published // Description: Returns the Unicode value of the nth character in the // stored text. This may be a wide character (greater @@ -1218,12 +1247,35 @@ get_num_chars() const { // according to set_encoding(). //////////////////////////////////////////////////////////////////// INLINE int TextNode:: -get_char(int index) const { +get_unicode_char(int index) const { get_wtext(); nassertr(index >= 0 && index < (int)_wtext.length(), 0); return _wtext[index]; } +//////////////////////////////////////////////////////////////////// +// Function: TextNode::get_encoded_char +// Access: Published +// Description: Returns the nth char of the stored text, as a one-, +// two-, or three-byte encoded string. +//////////////////////////////////////////////////////////////////// +INLINE string TextNode:: +get_encoded_char(int index) const { + return get_encoded_char(index, get_encoding()); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextNode::get_encoded_char +// Access: Published +// Description: Returns the nth char of the stored text, as a one-, +// two-, or three-byte encoded string. +//////////////////////////////////////////////////////////////////// +INLINE string TextNode:: +get_encoded_char(int index, TextNode::Encoding encoding) const { + wstring wch(1, (wchar_t)get_unicode_char(index)); + return encode_wtext(wch, encoding); +} + //////////////////////////////////////////////////////////////////// // Function: TextNode::get_text_as_ascii // Access: Published @@ -1248,6 +1300,21 @@ get_text_as_ascii() const { return encode_wtext(get_wtext_as_ascii()); } +//////////////////////////////////////////////////////////////////// +// Function: TextNode::reencode_text +// Access: Published, Static +// Description: Given the indicated text string, which is assumed to +// be encoded via the encoding "from", decodes it and +// then reencodes it into the encoding "to", and returns +// the newly encoded string. This does not change or +// affect any properties on the TextNode itself. +//////////////////////////////////////////////////////////////////// +INLINE string TextNode:: +reencode_text(const string &text, TextNode::Encoding from, + TextNode::Encoding to) { + return encode_wtext(decode_text(text, from), to); +} + //////////////////////////////////////////////////////////////////// // Function: TextNode::calc_width // Access: Published @@ -1491,6 +1558,28 @@ wordwrap_to(const wstring &wtext, float wordwrap_width, return _font->wordwrap_to(wtext, wordwrap_width, preserve_trailing_whitespace); } +//////////////////////////////////////////////////////////////////// +// Function: TextNode::encode_wtext +// Access: Public +// Description: Encodes a wide-text string into a single-char string, +// according to the current encoding. +//////////////////////////////////////////////////////////////////// +INLINE string TextNode:: +encode_wtext(const wstring &wtext) const { + return encode_wtext(wtext, _encoding); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextNode::decode_text +// Access: Public +// Description: Returns the given wstring decoded to a single-byte +// string, via the current encoding system. +//////////////////////////////////////////////////////////////////// +INLINE wstring TextNode:: +decode_text(const string &text) const { + return decode_text(text, _encoding); +} + //////////////////////////////////////////////////////////////////// // Function: TextNode::invalidate_no_measure // Access: Private diff --git a/panda/src/text/textNode.cxx b/panda/src/text/textNode.cxx index 4f7c14e277..962b898548 100644 --- a/panda/src/text/textNode.cxx +++ b/panda/src/text/textNode.cxx @@ -44,6 +44,8 @@ #include "cullTraverserData.h" #include "geometricBoundingVolume.h" #include "accumulatedAttribs.h" +#include "renderState.h" +#include "cullFaceAttrib.h" #include "dcast.h" #include @@ -466,18 +468,34 @@ get_wtext_as_ascii() const { //////////////////////////////////////////////////////////////////// // Function: TextNode::encode_wchar -// Access: Public +// Access: Public, Static // Description: Encodes a single wide char into a one-, two-, or -// three-byte string, according to the current encoding -// system in effect. +// three-byte string, according to the given encoding +// system. //////////////////////////////////////////////////////////////////// string TextNode:: -encode_wchar(wchar_t ch) const { - switch (_encoding) { +encode_wchar(wchar_t ch, TextNode::Encoding encoding) { + switch (encoding) { case E_iso8859: - if (isascii((unsigned int)ch)) { + if (ch < 0x100) { return string(1, (char)ch); } else { + // The character won't fit in the 8-bit ISO 8859. See if we can + // make it fit by reducing it to its ascii equivalent + // (essentially stripping off an unusual accent mark). + const UnicodeLatinMap::Entry *map_entry = + UnicodeLatinMap::look_up(ch); + if (map_entry != NULL && map_entry->_ascii_equiv != 0) { + // Yes, it has an ascii equivalent. + if (map_entry->_ascii_additional != 0) { + // In fact, it has two of them. + return + string(1, map_entry->_ascii_equiv) + + string(1, map_entry->_ascii_additional); + } + return string(1, map_entry->_ascii_equiv); + } + // Nope; return "." for lack of anything better. return "."; } @@ -506,16 +524,16 @@ encode_wchar(wchar_t ch) const { //////////////////////////////////////////////////////////////////// // Function: TextNode::encode_wtext -// Access: Public +// Access: Public, Static // Description: Encodes a wide-text string into a single-char string, -// accoding to the current encoding. +// according to the given encoding. //////////////////////////////////////////////////////////////////// string TextNode:: -encode_wtext(const wstring &wtext) const { +encode_wtext(const wstring &wtext, TextNode::Encoding encoding) { string result; for (wstring::const_iterator pi = wtext.begin(); pi != wtext.end(); ++pi) { - result += encode_wchar(*pi); + result += encode_wchar(*pi, encoding); } return result; @@ -523,13 +541,13 @@ encode_wtext(const wstring &wtext) const { //////////////////////////////////////////////////////////////////// // Function: TextNode::decode_text -// Access: Public +// Access: Public, Static // Description: Returns the given wstring decoded to a single-byte -// string, via the current encoding system. +// string, via the given encoding system. //////////////////////////////////////////////////////////////////// wstring TextNode:: -decode_text(const string &text) const { - switch (_encoding) { +decode_text(const string &text, TextNode::Encoding encoding) { + switch (encoding) { case E_utf8: { StringUtf8Decoder decoder(text); @@ -762,22 +780,24 @@ recompute_internal_bound() { //////////////////////////////////////////////////////////////////// // Function: TextNode::decode_text_impl -// Access: Private +// Access: Private, Static // Description: Decodes the eight-bit stream from the indicated // decoder, returning the decoded wide-char string. //////////////////////////////////////////////////////////////////// wstring TextNode:: -decode_text_impl(StringDecoder &decoder) const { +decode_text_impl(StringDecoder &decoder) { wstring result; - bool expand_amp = get_expand_amp(); + // bool expand_amp = get_expand_amp(); wchar_t character = decoder.get_next_character(); while (!decoder.is_eof()) { + /* if (character == '&' && expand_amp) { // An ampersand in expand_amp mode is treated as an escape // character. character = expand_amp_sequence(decoder); } + */ result += character; character = decoder.get_next_character(); } @@ -785,6 +805,7 @@ decode_text_impl(StringDecoder &decoder) const { return result; } +/* //////////////////////////////////////////////////////////////////// // Function: TextNode::expand_amp_sequence // Access: Private @@ -832,7 +853,7 @@ expand_amp_sequence(StringDecoder &decoder) const { int code; } tokens[] = { { "amp", '&' }, { "lt", '<' }, { "gt", '>' }, { "quot", '"' }, - { "nbsp", ' ' /* 160 */ }, + { "nbsp", ' ' }, { "iexcl", 161 }, { "cent", 162 }, { "pound", 163 }, { "curren", 164 }, { "yen", 165 }, { "brvbar", 166 }, { "brkbar", 166 }, { "sect", 167 }, @@ -873,6 +894,7 @@ expand_amp_sequence(StringDecoder &decoder) const { // Some unrecognized sequence. return 0; } +*/ //////////////////////////////////////////////////////////////////// @@ -1494,6 +1516,10 @@ tack_on_accent(char accent_mark, TextNode::CheesyPlacement placement, float t, u; LMatrix4f accent_mat; + // This gets set to true if the glyph gets mirrored and needs + // to have backface culling disabled. + bool mirrored = false; + switch (transform) { case CT_none: accent_mat = LMatrix4f::ident_mat(); @@ -1504,6 +1530,7 @@ tack_on_accent(char accent_mark, TextNode::CheesyPlacement placement, t = min_accent[0]; min_accent[0] = -max_accent[0]; max_accent[0] = -t; + mirrored = true; break; case CT_mirror_y: @@ -1511,6 +1538,7 @@ tack_on_accent(char accent_mark, TextNode::CheesyPlacement placement, t = min_accent[2]; min_accent[2] = -max_accent[2]; max_accent[2] = -t; + mirrored = true; break; case CT_rotate_90: @@ -1563,6 +1591,7 @@ tack_on_accent(char accent_mark, TextNode::CheesyPlacement placement, t = min_accent[2]; min_accent[2] = -max_accent[2] * squash_accent_scale_y; max_accent[2] = -t * squash_accent_scale_y; + mirrored = true; break; case CT_squash_mirror_diag: @@ -1577,6 +1606,7 @@ tack_on_accent(char accent_mark, TextNode::CheesyPlacement placement, max_accent[0] = max_accent[2] * -squash_accent_scale_x; min_accent[2] = -u * squash_accent_scale_y; max_accent[2] = -t * squash_accent_scale_y; + mirrored = true; break; case CT_small_squash: @@ -1594,6 +1624,7 @@ tack_on_accent(char accent_mark, TextNode::CheesyPlacement placement, t = min_accent[2]; min_accent[2] = -max_accent[2] * small_squash_accent_scale_y; max_accent[2] = -t * small_squash_accent_scale_y; + mirrored = true; break; case CT_small: @@ -1630,6 +1661,7 @@ tack_on_accent(char accent_mark, TextNode::CheesyPlacement placement, max_accent[0] = -t * tiny_accent_scale; min_accent[2] *= tiny_accent_scale; max_accent[2] *= tiny_accent_scale; + mirrored = true; break; case CT_tiny_rotate_270: @@ -1685,7 +1717,21 @@ tack_on_accent(char accent_mark, TextNode::CheesyPlacement placement, accent_mat.set_row(3, trans); accent_geom->transform_vertices(accent_mat); - dest->add_geom(accent_geom, accent_glyph->get_state()); + if (mirrored) { + // Once someone asks for this pointer, we hold its reference + // count and never free it. + static CPT(RenderState) disable_backface; + if (disable_backface == (const RenderState *)NULL) { + disable_backface = RenderState::make + (CullFaceAttrib::make(CullFaceAttrib::M_cull_none)); + } + + CPT(RenderState) state = + accent_glyph->get_state()->compose(disable_backface); + dest->add_geom(accent_geom, state); + } else { + dest->add_geom(accent_geom, accent_glyph->get_state()); + } geom_array[num_geoms++] = accent_geom; return true; diff --git a/panda/src/text/textNode.h b/panda/src/text/textNode.h index 69e792b789..1868eb5cb0 100644 --- a/panda/src/text/textNode.h +++ b/panda/src/text/textNode.h @@ -84,8 +84,10 @@ PUBLISHED: INLINE static void set_default_encoding(Encoding encoding); INLINE static Encoding get_default_encoding(); + /* INLINE void set_expand_amp(bool expand_amp); INLINE bool get_expand_amp() const; + */ INLINE float get_line_height() const; @@ -180,15 +182,21 @@ PUBLISHED: INLINE CoordinateSystem get_coordinate_system() const; INLINE void set_text(const string &text); + INLINE void set_text(const string &text, Encoding encoding); INLINE void clear_text(); INLINE bool has_text() const; INLINE string get_text() const; + INLINE string get_text(Encoding encoding) const; INLINE void append_text(const string &text); - INLINE void append_char(int character); + INLINE void append_unicode_char(int character); INLINE int get_num_chars() const; - INLINE int get_char(int index) const; + INLINE int get_unicode_char(int index) const; + INLINE string get_encoded_char(int index) const; + INLINE string get_encoded_char(int index, Encoding encoding) const; INLINE string get_text_as_ascii() const; + INLINE static string reencode_text(const string &text, Encoding from, Encoding to); + INLINE float calc_width(int character) const; INLINE float calc_width(const string &line) const; string wordwrap_to(const string &text, float wordwrap_width, @@ -225,9 +233,11 @@ public: INLINE wstring wordwrap_to(const wstring &wtext, float wordwrap_width, bool preserve_trailing_whitespace) const; - string encode_wchar(wchar_t ch) const; - string encode_wtext(const wstring &wtext) const; - wstring decode_text(const string &text) const; + static string encode_wchar(wchar_t ch, Encoding encoding); + INLINE string encode_wtext(const wstring &wtext) const; + static string encode_wtext(const wstring &wtext, Encoding encoding); + INLINE wstring decode_text(const string &text) const; + static wstring decode_text(const string &text, Encoding encoding); // From parent class PandaNode virtual int get_unsafe_to_apply_attribs() const; @@ -245,8 +255,8 @@ public: virtual BoundingVolume *recompute_internal_bound(); private: - wstring decode_text_impl(StringDecoder &decoder) const; - int expand_amp_sequence(StringDecoder &decoder) const; + static wstring decode_text_impl(StringDecoder &decoder); + // int expand_amp_sequence(StringDecoder &decoder) const; INLINE void invalidate_no_measure(); INLINE void invalidate_with_measure(); @@ -344,7 +354,7 @@ private: F_frame_corners = 0x00000100, F_card_transp = 0x00000200, F_has_card_border = 0x00000400, - F_expand_amp = 0x00000800, + // F_expand_amp = 0x00000800, F_got_text = 0x00001000, F_got_wtext = 0x00002000, F_needs_rebuild = 0x00004000,