2
0
Эх сурвалжийг харах

more control over encoding

David Rose 23 жил өмнө
parent
commit
9aeeb1ce1a

+ 94 - 5
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

+ 65 - 19
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 <stdio.h>
@@ -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;

+ 18 - 8
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,