Browse Source

Overhaul text generation; now 75x as fast as before.

rdb 10 years ago
parent
commit
a453ec1925

+ 5 - 1
dtool/src/dtoolutil/unicodeLatinMap.cxx

@@ -369,6 +369,8 @@ static const UnicodeLatinMap::Entry latin_map[] = {
     UnicodeLatinMap::AT_none, UnicodeLatinMap::AF_reversed },
   { 0x0258, UnicodeLatinMap::CT_lower, 'e', 0, 0x0258, 0x018e,
     UnicodeLatinMap::AT_none, UnicodeLatinMap::AF_reversed },
+  { 0x0259, UnicodeLatinMap::CT_lower, 'e', 0, 0x0259, 0x018f,
+    UnicodeLatinMap::AT_none, UnicodeLatinMap::AF_turned },
   { 0x0066, UnicodeLatinMap::CT_lower, 'f', 0, 0x0066, 0x0046,
     UnicodeLatinMap::AT_none, 0 },
   { 0x0046, UnicodeLatinMap::CT_upper, 'F', 0, 0x0066, 0x0046,
@@ -465,7 +467,9 @@ static const UnicodeLatinMap::Entry latin_map[] = {
     UnicodeLatinMap::AT_line_below, 0 },
   { 0x029c, UnicodeLatinMap::CT_upper, 'H', 0, 0x0068, 0x029c,
     UnicodeLatinMap::AT_none, UnicodeLatinMap::AF_smallcap },
-  { 0x0195, UnicodeLatinMap::CT_lower, 'h', 'v', 0x0195, 0x195,
+  { 0x0195, UnicodeLatinMap::CT_lower, 'h', 'v', 0x0195, 0x01f6,
+    UnicodeLatinMap::AT_none, UnicodeLatinMap::AF_ligature },
+  { 0x01f6, UnicodeLatinMap::CT_upper, 'H', 'v', 0x0195, 0x01f6,
     UnicodeLatinMap::AT_none, UnicodeLatinMap::AF_ligature },
   { 0x0127, UnicodeLatinMap::CT_lower, 'h', 0, 0x0127, 0x0126,
     UnicodeLatinMap::AT_stroke, 0 },

+ 1 - 1
panda/src/express/pointerToBase.I

@@ -162,7 +162,7 @@ update_type(To *ptr) {
 //               (Assignment to a NULL pointer also works, of course.)
 ////////////////////////////////////////////////////////////////////
 template<class T>
-INLINE void PointerToBase<T>::
+ALWAYS_INLINE void PointerToBase<T>::
 clear() {
   reassign((To *)NULL);
 }

+ 1 - 1
panda/src/express/pointerToBase.h

@@ -55,7 +55,7 @@ protected:
   // vs. non-const later.
 
 PUBLISHED:
-  INLINE void clear();
+  ALWAYS_INLINE void clear();
 
   void output(ostream &out) const;
 };

+ 1 - 1
panda/src/express/pointerToVoid.I

@@ -50,7 +50,7 @@ PointerToVoid(const PointerToVoid &) {
 //               false otherwise.  (Direct comparison to a NULL
 //               pointer also works.)
 ////////////////////////////////////////////////////////////////////
-INLINE bool PointerToVoid::
+ALWAYS_INLINE bool PointerToVoid::
 is_null() const {
   return (_void_ptr == (void *)NULL);
 }

+ 1 - 1
panda/src/express/pointerToVoid.h

@@ -42,7 +42,7 @@ private:
   INLINE PointerToVoid(const PointerToVoid &copy);
 
 PUBLISHED:
-  INLINE bool is_null() const;
+  ALWAYS_INLINE bool is_null() const;
   INLINE size_t get_hash() const;
 
 public:

+ 14 - 4
panda/src/text/dynamicTextFont.I

@@ -260,8 +260,18 @@ get_poly_margin() const {
 ////////////////////////////////////////////////////////////////////
 INLINE void DynamicTextFont::
 set_page_size(int x_size, int y_size) {
-  _page_x_size = x_size;
-  _page_y_size = y_size;
+  _page_size.set(x_size, y_size);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DynamicTextFont::get_page_size
+//       Access: Published
+//  Description: Returns the size of the textures that are created
+//               for the DynamicTextFont.  See set_page_size().
+////////////////////////////////////////////////////////////////////
+INLINE const LVecBase2i &DynamicTextFont::
+get_page_size() const {
+  return _page_size;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -272,7 +282,7 @@ set_page_size(int x_size, int y_size) {
 ////////////////////////////////////////////////////////////////////
 INLINE int DynamicTextFont::
 get_page_x_size() const {
-  return _page_x_size;
+  return _page_size.get_x();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -283,7 +293,7 @@ get_page_x_size() const {
 ////////////////////////////////////////////////////////////////////
 INLINE int DynamicTextFont::
 get_page_y_size() const {
-  return _page_y_size;
+  return _page_size.get_y();
 }
 
 ////////////////////////////////////////////////////////////////////

+ 63 - 30
panda/src/text/dynamicTextFont.cxx

@@ -44,6 +44,8 @@
 #include "nurbsCurveResult.h"
 //#include "renderModeAttrib.h"
 //#include "antialiasAttrib.h"
+#include "colorAttrib.h"
+#include "textureAttrib.h"
 
 TypeHandle DynamicTextFont::_type_handle;
 
@@ -110,8 +112,7 @@ DynamicTextFont(const DynamicTextFont &copy) :
   FreetypeFont(copy),
   _texture_margin(copy._texture_margin),
   _poly_margin(copy._poly_margin),
-  _page_x_size(copy._page_x_size),
-  _page_y_size(copy._page_y_size),
+  _page_size(copy._page_size),
   _minfilter(copy._minfilter),
   _magfilter(copy._magfilter),
   _anisotropic_degree(copy._anisotropic_degree),
@@ -194,8 +195,8 @@ garbage_collect() {
   Cache new_cache;
   Cache::iterator ci;
   for (ci = _cache.begin(); ci != _cache.end(); ++ci) {
-    DynamicTextGlyph *glyph = (*ci).second;
-    if (glyph == (DynamicTextGlyph *)NULL || glyph->_geom_count != 0) {
+    TextGlyph *glyph = (*ci).second;
+    if (glyph == (TextGlyph *)NULL || glyph->get_ref_count() > 1) {
       // Keep this one.
       new_cache.insert(new_cache.end(), (*ci));
     } else {
@@ -252,7 +253,7 @@ write(ostream &out, int indent_level) const {
   Cache::const_iterator ci;
   for (ci = _cache.begin(); ci != _cache.end(); ++ci) {
     int glyph_index = (*ci).first;
-    DynamicTextGlyph *glyph = (*ci).second;
+    TextGlyph *glyph = (*ci).second;
     indent(out, indent_level + 2) 
       << glyph_index;
 
@@ -269,7 +270,7 @@ write(ostream &out, int indent_level) const {
     }
     release_face(face);
 
-    out << ", count = " << glyph->_geom_count << "\n";
+    out << '\n';
   }
 }
 
@@ -285,7 +286,7 @@ write(ostream &out, int indent_level) const {
 //               printable glyph.
 ////////////////////////////////////////////////////////////////////
 bool DynamicTextFont::
-get_glyph(int character, const TextGlyph *&glyph) {
+get_glyph(int character, CPT(TextGlyph) &glyph) {
   if (!_is_valid) {
     glyph = (TextGlyph *)NULL;
     return false;
@@ -302,12 +303,12 @@ get_glyph(int character, const TextGlyph *&glyph) {
   if (ci != _cache.end()) {
     glyph = (*ci).second;
   } else {
-    DynamicTextGlyph *dynamic_glyph = make_glyph(character, face, glyph_index);
+    TextGlyph *dynamic_glyph = make_glyph(character, face, glyph_index);
     _cache.insert(Cache::value_type(glyph_index, dynamic_glyph));
     glyph = dynamic_glyph;
   }
 
-  if (glyph == (DynamicTextGlyph *)NULL) {
+  if (glyph == (TextGlyph *)NULL) {
     glyph = get_invalid_glyph();
     glyph_index = 0;
   }
@@ -327,8 +328,7 @@ void DynamicTextFont::
 initialize() {
   _texture_margin = text_texture_margin;
   _poly_margin = text_poly_margin;
-  _page_x_size = text_page_size[0];
-  _page_y_size = text_page_size[1];
+  _page_size.set(text_page_size[0], text_page_size[1]);
 
   // We don't necessarily want to use mipmaps, since we don't want to
   // regenerate those every time the texture changes, but we probably
@@ -442,10 +442,10 @@ determine_tex_format() {
 //               newly-created TextGlyph object, or NULL if the
 //               glyph cannot be created for some reason.
 ////////////////////////////////////////////////////////////////////
-DynamicTextGlyph *DynamicTextFont::
+TextGlyph *DynamicTextFont::
 make_glyph(int character, FT_Face face, int glyph_index) {
   if (!load_glyph(face, glyph_index, false)) {
-    return (DynamicTextGlyph *)NULL;
+    return (TextGlyph *)NULL;
   }
 
   FT_GlyphSlot slot = face->glyph;
@@ -461,6 +461,7 @@ make_glyph(int character, FT_Face face, int glyph_index) {
   }
 
   PN_stdfloat advance = slot->advance.x / 64.0;
+  advance /= _font_pixels_per_unit;
 
   if (_render_mode != RM_texture && 
       slot->format == ft_glyph_format_outline) {
@@ -520,8 +521,8 @@ make_glyph(int character, FT_Face face, int glyph_index) {
     _contours.clear();
     FT_Outline_Decompose(&slot->outline, &funcs, (void *)this);
 
-    PT(DynamicTextGlyph) glyph = 
-      new DynamicTextGlyph(character, advance / _font_pixels_per_unit);
+    PT(TextGlyph) glyph =
+      new TextGlyph(character, advance);
     switch (_render_mode) {
     case RM_wireframe:
       render_wireframe_contours(glyph);
@@ -553,8 +554,8 @@ make_glyph(int character, FT_Face face, int glyph_index) {
   if (bitmap.width == 0 || bitmap.rows == 0) {
     // If we got an empty bitmap, it's a special case.
 
-    PT(DynamicTextGlyph) glyph = 
-      new DynamicTextGlyph(character, advance / _font_pixels_per_unit);
+    PT(TextGlyph) glyph =
+      new TextGlyph(character, advance);
     _empty_glyphs.push_back(glyph);
     return glyph;
 
@@ -571,7 +572,7 @@ make_glyph(int character, FT_Face face, int glyph_index) {
       // If the bitmap produced from the font doesn't require scaling
       // or any other processing before it goes to the texture, we can
       // just copy it directly into the texture.
-      glyph = slot_glyph(character, bitmap.width, bitmap.rows);
+      glyph = slot_glyph(character, bitmap.width, bitmap.rows, advance);
       copy_bitmap_to_texture(bitmap, glyph);
 
     } else {
@@ -599,7 +600,7 @@ make_glyph(int character, FT_Face face, int glyph_index) {
       int_y_size += outline * 2;
       tex_x_size += outline * 2;
       tex_y_size += outline * 2;
-      glyph = slot_glyph(character, int_x_size, int_y_size);
+      glyph = slot_glyph(character, int_x_size, int_y_size, advance);
 
       if (outline != 0) {
         // Pad the glyph image to make room for the outline.
@@ -612,11 +613,43 @@ make_glyph(int character, FT_Face face, int glyph_index) {
       }
     }
 
-    glyph->make_geom((int)floor(slot->bitmap_top + outline * _scale_factor + 0.5f),
-                     (int)floor(slot->bitmap_left - outline * _scale_factor + 0.5f),
-                     advance, _poly_margin,
-                     tex_x_size, tex_y_size,
-                     _font_pixels_per_unit, _tex_pixels_per_unit);
+    DynamicTextPage *page = glyph->get_page();
+    if (page != NULL) {
+      int bitmap_top = (int)floor(slot->bitmap_top + outline * _scale_factor + 0.5f);
+      int bitmap_left = (int)floor(slot->bitmap_left - outline * _scale_factor + 0.5f);
+
+      tex_x_size += glyph->_margin * 2;
+      tex_y_size += glyph->_margin * 2;
+
+      // Determine the corners of the rectangle in geometric units.
+      PN_stdfloat tex_poly_margin = _poly_margin / _tex_pixels_per_unit;
+      PN_stdfloat origin_y = bitmap_top / _font_pixels_per_unit;
+      PN_stdfloat origin_x = bitmap_left / _font_pixels_per_unit;
+
+      LVecBase4 dimensions(
+        origin_x - tex_poly_margin,
+        origin_y - tex_y_size / _tex_pixels_per_unit - tex_poly_margin,
+        origin_x + tex_x_size / _tex_pixels_per_unit + tex_poly_margin,
+        origin_y + tex_poly_margin);
+
+      // And the corresponding corners in UV units.  We add 0.5f to center
+      // the UV in the middle of its texel, to minimize roundoff errors
+      // when we are close to 1-to-1 pixel size.
+      LVecBase2i page_size = page->get_size();
+      LVecBase4 texcoords(
+        ((PN_stdfloat)(glyph->_x - _poly_margin) + 0.5f) / page_size[0],
+        1.0f - ((PN_stdfloat)(glyph->_y + _poly_margin + tex_y_size) + 0.5f) / page_size[1],
+        ((PN_stdfloat)(glyph->_x + _poly_margin + tex_x_size) + 0.5f) / page_size[0],
+        1.0f - ((PN_stdfloat)(glyph->_y - _poly_margin) + 0.5f) / page_size[1]);
+
+      CPT(RenderState) state;
+      state = RenderState::make(TextureAttrib::make(page),
+                                TransparencyAttrib::make(TransparencyAttrib::M_alpha));
+      state = state->add_attrib(ColorAttrib::make_flat(LColor(1.0f, 1.0f, 1.0f, 1.0f)), -1);
+
+      glyph->set_quad(dimensions, texcoords, state);
+    }
+
     return glyph;
   }
 }
@@ -835,7 +868,7 @@ blend_pnmimage_to_texture(const PNMImage &image, DynamicTextGlyph *glyph,
 //               filled in yet except with its size.
 ////////////////////////////////////////////////////////////////////
 DynamicTextGlyph *DynamicTextFont::
-slot_glyph(int character, int x_size, int y_size) {
+slot_glyph(int character, int x_size, int y_size, PN_stdfloat advance) {
   // Increase the indicated size by the current margin.
   x_size += _texture_margin * 2;
   y_size += _texture_margin * 2;
@@ -850,7 +883,7 @@ slot_glyph(int character, int x_size, int y_size) {
 
     do {
       DynamicTextPage *page = _pages[pi];
-      DynamicTextGlyph *glyph = page->slot_glyph(character, x_size, y_size, _texture_margin);
+      DynamicTextGlyph *glyph = page->slot_glyph(character, x_size, y_size, _texture_margin, advance);
       if (glyph != (DynamicTextGlyph *)NULL) {
         // Once we found a page to hold the glyph, that becomes our
         // new preferred page.
@@ -874,7 +907,7 @@ slot_glyph(int character, int x_size, int y_size) {
   // glyphs?
   if (garbage_collect() != 0) {
     // Yes, we just freed up some space.  Try once more, recursively.
-    return slot_glyph(character, x_size, y_size);
+    return slot_glyph(character, x_size, y_size, advance);
 
   } else {
     // No good; all recorded glyphs are actually in use.  We need to
@@ -882,7 +915,7 @@ slot_glyph(int character, int x_size, int y_size) {
     _preferred_page = _pages.size();
     PT(DynamicTextPage) page = new DynamicTextPage(this, _preferred_page);
     _pages.push_back(page);
-    return page->slot_glyph(character, x_size, y_size, _texture_margin);
+    return page->slot_glyph(character, x_size, y_size, _texture_margin, advance);
   }
 }
 
@@ -893,7 +926,7 @@ slot_glyph(int character, int x_size, int y_size) {
 //               geometry, as a wireframe render.
 ////////////////////////////////////////////////////////////////////
 void DynamicTextFont::
-render_wireframe_contours(DynamicTextGlyph *glyph) {
+render_wireframe_contours(TextGlyph *glyph) {
   PT(GeomVertexData) vdata = new GeomVertexData
     (string(), GeomVertexFormat::get_v3(),
      Geom::UH_static);
@@ -926,7 +959,7 @@ render_wireframe_contours(DynamicTextGlyph *glyph) {
 //               geometry, as a polygon render.
 ////////////////////////////////////////////////////////////////////
 void DynamicTextFont::
-render_polygon_contours(DynamicTextGlyph *glyph, bool face, bool extrude) {
+render_polygon_contours(TextGlyph *glyph, bool face, bool extrude) {
   PT(GeomVertexData) vdata = new GeomVertexData
     (string(), GeomVertexFormat::get_v3n3(),
      Geom::UH_static);

+ 9 - 8
panda/src/text/dynamicTextFont.h

@@ -74,6 +74,7 @@ PUBLISHED:
   INLINE PN_stdfloat get_poly_margin() const;
 
   INLINE void set_page_size(int x_size, int y_size);
+  INLINE const LVecBase2i &get_page_size() const;
   INLINE int get_page_x_size() const;
   INLINE int get_page_y_size() const;
 
@@ -110,21 +111,21 @@ PUBLISHED:
   virtual void write(ostream &out, int indent_level) const;
 
 public:
-  virtual bool get_glyph(int character, const TextGlyph *&glyph);
+  virtual bool get_glyph(int character, CPT(TextGlyph) &glyph);
 
 private:
   void initialize();
   void update_filters();
   void determine_tex_format();
-  DynamicTextGlyph *make_glyph(int character, FT_Face face, int glyph_index);
+  TextGlyph *make_glyph(int character, FT_Face face, int glyph_index);
   void copy_bitmap_to_texture(const FT_Bitmap &bitmap, DynamicTextGlyph *glyph);
   void copy_pnmimage_to_texture(const PNMImage &image, DynamicTextGlyph *glyph);
   void blend_pnmimage_to_texture(const PNMImage &image, DynamicTextGlyph *glyph,
                                  const LColor &fg);
-  DynamicTextGlyph *slot_glyph(int character, int x_size, int y_size);
+  DynamicTextGlyph *slot_glyph(int character, int x_size, int y_size, PN_stdfloat advance);
 
-  void render_wireframe_contours(DynamicTextGlyph *glyph);
-  void render_polygon_contours(DynamicTextGlyph *glyph, bool face, bool extrude);
+  void render_wireframe_contours(TextGlyph *glyph);
+  void render_polygon_contours(TextGlyph *glyph, bool face, bool extrude);
 
   static int outline_move_to(const FT_Vector *to, void *user);
   static int outline_line_to(const FT_Vector *to, void *user);
@@ -137,7 +138,7 @@ private:
 
   int _texture_margin;
   PN_stdfloat _poly_margin;
-  int _page_x_size, _page_y_size;
+  LVecBase2i _page_size;
 
   SamplerState::FilterType _minfilter;
   SamplerState::FilterType _magfilter;
@@ -159,14 +160,14 @@ private:
 
   // This doesn't need to be a reference-counting pointer, because the
   // reference to each glyph is kept by the DynamicTextPage object.
-  typedef pmap<int, DynamicTextGlyph *> Cache;
+  typedef pmap<int, TextGlyph *> Cache;
   Cache _cache;
 
   // This is a list of the glyphs that do not have any printable
   // properties (e.g. space), but still have an advance measure.  We
   // store them here to keep their reference counts; they also appear
   // in the above table.
-  typedef pvector< PT(DynamicTextGlyph) > EmptyGlyphs;
+  typedef pvector< PT(TextGlyph) > EmptyGlyphs;
   EmptyGlyphs _empty_glyphs;
 
   class ContourPoint {

+ 25 - 30
panda/src/text/dynamicTextGlyph.I

@@ -21,16 +21,13 @@
 ////////////////////////////////////////////////////////////////////
 INLINE DynamicTextGlyph::
 DynamicTextGlyph(int character, DynamicTextPage *page, int x, int y,
-                 int x_size, int y_size, int margin) :
-  TextGlyph(character),
+                 int x_size, int y_size, int margin, PN_stdfloat advance) :
+  TextGlyph(character, advance),
   _page(page),
   _x(x), _y(y),
   _x_size(x_size), _y_size(y_size),
-  _margin(margin),
-  _top(0), _left(0), _bottom(0), _right(0),
-  _uv_top(0), _uv_left(0), _uv_bottom(0), _uv_right(0)
+  _margin(margin)
 {
-  _geom_count = 0;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -42,14 +39,12 @@ DynamicTextGlyph(int character, DynamicTextPage *page, int x, int y,
 ////////////////////////////////////////////////////////////////////
 INLINE DynamicTextGlyph::
 DynamicTextGlyph(int character, PN_stdfloat advance) :
-  TextGlyph(character),
+  TextGlyph(character, advance),
   _page((DynamicTextPage *)NULL),
   _x(0), _y(0),
   _x_size(0), _y_size(0),
   _margin(0)
 {
-  _advance = advance;
-  _geom_count = 1;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -105,17 +100,6 @@ intersects(int x, int y, int x_size, int y_size) const {
            y >= mbot || hbot <= _y);
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: DynamicTextGlyph::get_top
-//       Access: Published
-//  Description: Returns the vertex coordinates that can be used when
-//               creating a custom text renderer.
-////////////////////////////////////////////////////////////////////
-INLINE PN_stdfloat DynamicTextGlyph::
-get_top() const {
-  return _top;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: DynamicTextGlyph::get_left
 //       Access: Published
@@ -124,7 +108,7 @@ get_top() const {
 ////////////////////////////////////////////////////////////////////
 INLINE PN_stdfloat DynamicTextGlyph::
 get_left() const {
-  return _left;
+  return _quad_dimensions[0];
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -135,7 +119,7 @@ get_left() const {
 ////////////////////////////////////////////////////////////////////
 INLINE PN_stdfloat DynamicTextGlyph::
 get_bottom() const {
-  return _bottom;
+  return _quad_dimensions[1];
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -146,18 +130,18 @@ get_bottom() const {
 ////////////////////////////////////////////////////////////////////
 INLINE PN_stdfloat DynamicTextGlyph::
 get_right() const {
-  return _right;
+  return _quad_dimensions[2];
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DynamicTextGlyph::get_uv_top
+//     Function: DynamicTextGlyph::get_top
 //       Access: Published
-//  Description: Returns the UV coordinates that can be used when
+//  Description: Returns the vertex coordinates that can be used when
 //               creating a custom text renderer.
 ////////////////////////////////////////////////////////////////////
 INLINE PN_stdfloat DynamicTextGlyph::
-get_uv_top() const {
-  return _uv_top;
+get_top() const {
+  return _quad_dimensions[3];
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -168,7 +152,7 @@ get_uv_top() const {
 ////////////////////////////////////////////////////////////////////
 INLINE PN_stdfloat DynamicTextGlyph::
 get_uv_left() const {
-  return _uv_left;
+  return _quad_texcoords[0];
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -179,7 +163,7 @@ get_uv_left() const {
 ////////////////////////////////////////////////////////////////////
 INLINE PN_stdfloat DynamicTextGlyph::
 get_uv_bottom() const {
-  return _uv_bottom;
+  return _quad_texcoords[1];
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -190,5 +174,16 @@ get_uv_bottom() const {
 ////////////////////////////////////////////////////////////////////
 INLINE PN_stdfloat DynamicTextGlyph::
 get_uv_right() const {
-  return _uv_right;
+  return _quad_texcoords[2];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DynamicTextGlyph::get_uv_top
+//       Access: Published
+//  Description: Returns the UV coordinates that can be used when
+//               creating a custom text renderer.
+////////////////////////////////////////////////////////////////////
+INLINE PN_stdfloat DynamicTextGlyph::
+get_uv_top() const {
+  return _quad_texcoords[3];
 }

+ 0 - 112
panda/src/text/dynamicTextGlyph.cxx

@@ -87,118 +87,6 @@ erase(DynamicTextFont *font) {
                      font->get_bg());
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: DynamicTextGlyph::make_geom
-//       Access: Public
-//  Description: Creates the actual geometry for the glyph.  The
-//               parameters bitmap_top and bitmap_left are from
-//               FreeType, and indicate the position of the top left
-//               corner of the bitmap relative to the glyph's origin.
-//               The advance number represents the number of pixels
-//               the pen should be advanced after drawing this glyph.
-////////////////////////////////////////////////////////////////////
-void DynamicTextGlyph::
-make_geom(int bitmap_top, int bitmap_left, PN_stdfloat advance, PN_stdfloat poly_margin, 
-          PN_stdfloat tex_x_size, PN_stdfloat tex_y_size,
-          PN_stdfloat font_pixels_per_unit, PN_stdfloat tex_pixels_per_unit) {
-  nassertv(_page != (DynamicTextPage *)NULL);
-
-  // This function should not be called twice.
-  nassertv(_geom_count == 0);
-
-  tex_x_size += _margin * 2;
-  tex_y_size += _margin * 2;
-
-  // Determine the corners of the rectangle in geometric units.
-  PN_stdfloat tex_poly_margin = poly_margin / tex_pixels_per_unit;
-  PN_stdfloat origin_y = bitmap_top / font_pixels_per_unit;
-  PN_stdfloat origin_x = bitmap_left / font_pixels_per_unit;
-  _top = origin_y + tex_poly_margin;
-  _left = origin_x - tex_poly_margin;
-  _bottom = origin_y - tex_y_size / tex_pixels_per_unit - tex_poly_margin;
-  _right = origin_x + tex_x_size / tex_pixels_per_unit + tex_poly_margin;
-
-  // And the corresponding corners in UV units.  We add 0.5f to center
-  // the UV in the middle of its texel, to minimize roundoff errors
-  // when we are close to 1-to-1 pixel size.
-  _uv_top = 1.0f - ((PN_stdfloat)(_y - poly_margin) + 0.5f) / _page->get_y_size();
-  _uv_left = ((PN_stdfloat)(_x - poly_margin) + 0.5f) / _page->get_x_size();
-  _uv_bottom = 1.0f - ((PN_stdfloat)(_y + poly_margin + tex_y_size) + 0.5f) / _page->get_y_size();
-  _uv_right = ((PN_stdfloat)(_x + poly_margin + tex_x_size) + 0.5f) / _page->get_x_size();
-
-  // Create a corresponding triangle pair.  We use a pair of indexed
-  // triangles rather than a single triangle strip, to avoid the bad
-  // vertex duplication behavior with lots of two-triangle strips.
-  PT(GeomVertexData) vdata = new GeomVertexData
-    (string(), GeomVertexFormat::get_v3t2(),
-     Geom::UH_static);
-  vdata->unclean_set_num_rows(4);
-
-  GeomVertexWriter vertex(vdata, InternalName::get_vertex());
-  GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
-  
-  vertex.add_data3(_left, 0, _top);
-  vertex.add_data3(_left, 0, _bottom);
-  vertex.add_data3(_right, 0, _top);
-  vertex.add_data3(_right, 0, _bottom);
-  
-  texcoord.add_data2(_uv_left, _uv_top);
-  texcoord.add_data2(_uv_left, _uv_bottom);
-  texcoord.add_data2(_uv_right, _uv_top);
-  texcoord.add_data2(_uv_right, _uv_bottom);
-  
-  PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static);
-  tris->reserve_num_vertices(6);
-  tris->add_vertex(0);
-  tris->add_vertex(1);
-  tris->add_vertex(2);
-  tris->close_primitive();
-  tris->add_vertex(2);
-  tris->add_vertex(1);
-  tris->add_vertex(3);
-  tris->close_primitive();
-
-  PT(Geom) geom = new GeomTextGlyph(this, vdata);
-  geom->add_primitive(tris);
-  _geom = geom;
-  
-  // The above will increment our _geom_count to 1.  Reset it back
-  // down to 0, since our own internal Geom doesn't count.
-  nassertv(_geom_count == 1);
-  _geom_count--;
-  
-  _state = RenderState::make(TextureAttrib::make(_page),
-                             TransparencyAttrib::make(TransparencyAttrib::M_alpha));
-  _state = _state->add_attrib(ColorAttrib::make_flat(LColor(1.0f, 1.0f, 1.0f, 1.0f)), -1);
-  
-  _advance = advance / font_pixels_per_unit;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DynamicTextGlyph::set_geom
-//       Access: Public
-//  Description: Sets the geom from a pre-built object.
-////////////////////////////////////////////////////////////////////
-void DynamicTextGlyph::
-set_geom(GeomVertexData *vdata, GeomPrimitive *prim, 
-         const RenderState *state) {
-  // This function is called when _geom_count = 1, because it was
-  // constructed via the empty Glyph constructor.
-  nassertv(_geom_count == 1);
-  _geom_count--;
-
-  PT(Geom) geom = new GeomTextGlyph(this, vdata);
-  geom->add_primitive(prim);
-  _geom = geom;
-  
-  // The above will increment our _geom_count to 1.  Reset it back
-  // down to 0, since our own internal Geom doesn't count.
-  nassertv(_geom_count == 1);
-  _geom_count--;
-  
-  _state = state;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: DynamicTextGlyph::is_whitespace
 //       Access: Public, Virtual

+ 5 - 11
panda/src/text/dynamicTextGlyph.h

@@ -35,7 +35,7 @@ class EXPCL_PANDA_TEXT DynamicTextGlyph : public TextGlyph {
 public:
   INLINE DynamicTextGlyph(int character, DynamicTextPage *page,
                           int x, int y, int x_size, int y_size, 
-                          int margin);
+                          int margin, PN_stdfloat advance);
   INLINE DynamicTextGlyph(int character, PN_stdfloat advance);
 private:
   INLINE DynamicTextGlyph(const DynamicTextGlyph &copy);
@@ -48,34 +48,28 @@ PUBLISHED:
 
   INLINE bool intersects(int x, int y, int x_size, int y_size) const;
 
-  INLINE PN_stdfloat get_top() const;
   INLINE PN_stdfloat get_left() const;
   INLINE PN_stdfloat get_bottom() const;
   INLINE PN_stdfloat get_right() const;
+  INLINE PN_stdfloat get_top() const;
 
-  INLINE PN_stdfloat get_uv_top() const;
   INLINE PN_stdfloat get_uv_left() const;
   INLINE PN_stdfloat get_uv_bottom() const;
   INLINE PN_stdfloat get_uv_right() const;
+  INLINE PN_stdfloat get_uv_top() const;
 
 public:
   unsigned char *get_row(int y);
   void erase(DynamicTextFont *font);
-  void make_geom(int top, int left, PN_stdfloat advance, PN_stdfloat poly_margin,
-                 PN_stdfloat tex_x_size, PN_stdfloat tex_y_size,
-                 PN_stdfloat font_pixels_per_unit, PN_stdfloat tex_pixels_per_unit);
-  void set_geom(GeomVertexData *vdata, GeomPrimitive *prim, 
-                const RenderState *state);
   virtual bool is_whitespace() const;
 
   DynamicTextPage *_page;
-  int _geom_count;
 
   int _x, _y;
   int _x_size, _y_size;
   int _margin;
-  PN_stdfloat _top, _left, _bottom, _right;
-  PN_stdfloat _uv_top, _uv_left, _uv_bottom, _uv_right;
+
+  friend class DynamicTextFont;
 
 public:
   static TypeHandle get_class_type() {

+ 12 - 3
panda/src/text/dynamicTextPage.I

@@ -13,6 +13,16 @@
 ////////////////////////////////////////////////////////////////////
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: DynamicTextPage::get_size
+//       Access: Published
+//  Description: Returns the size of the page (texture), in pixels.
+////////////////////////////////////////////////////////////////////
+INLINE const LVecBase2i &DynamicTextPage::
+get_size() const {
+  return _size;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DynamicTextPage::get_x_size
 //       Access: Published
@@ -20,7 +30,7 @@
 ////////////////////////////////////////////////////////////////////
 INLINE int DynamicTextPage::
 get_x_size() const {
-  return _x_size;
+  return _size.get_x();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -30,10 +40,9 @@ get_x_size() const {
 ////////////////////////////////////////////////////////////////////
 INLINE int DynamicTextPage::
 get_y_size() const {
-  return _y_size;
+  return _size.get_y();
 }
 
-
 ////////////////////////////////////////////////////////////////////
 //     Function: DynamicTextPage::is_empty
 //       Access: Published

+ 17 - 16
panda/src/text/dynamicTextPage.cxx

@@ -38,10 +38,9 @@ DynamicTextPage(DynamicTextFont *font, int page_number) :
   // doesn't usually have a high fill factor.
   set_quality_level(text_quality_level);
 
-  _x_size = _font->get_page_x_size();
-  _y_size = _font->get_page_y_size();
+  _size = _font->get_page_size();
 
-  setup_2d_texture(_x_size, _y_size, T_unsigned_byte, font->get_tex_format());
+  setup_2d_texture(_size[0], _size[1], T_unsigned_byte, font->get_tex_format());
 
   // Assign a name to the Texture.
   ostringstream strm;
@@ -63,7 +62,7 @@ DynamicTextPage(DynamicTextFont *font, int page_number) :
   set_border_color(font->get_bg());
 
   // Fill the page with the font's background color.
-  fill_region(0, 0, _x_size, _y_size, font->get_bg());
+  fill_region(0, 0, _size[0], _size[1], font->get_bg());
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -74,7 +73,8 @@ DynamicTextPage(DynamicTextFont *font, int page_number) :
 //               glyph object and returns it; otherwise, returns NULL.
 ////////////////////////////////////////////////////////////////////
 DynamicTextGlyph *DynamicTextPage::
-slot_glyph(int character, int x_size, int y_size, int margin) {
+slot_glyph(int character, int x_size, int y_size, int margin,
+           PN_stdfloat advance) {
   int x, y;
   if (!find_hole(x, y, x_size, y_size)) {
     // No room for the glyph.
@@ -84,7 +84,7 @@ slot_glyph(int character, int x_size, int y_size, int margin) {
   // The glyph can be fit at (x, y).  Slot it.
   PT(DynamicTextGlyph) glyph = 
     new DynamicTextGlyph(character, this,
-                         x, y, x_size, y_size, margin);
+                         x, y, x_size, y_size, margin, advance);
   _glyphs.push_back(glyph);
   return glyph;
 }
@@ -97,7 +97,7 @@ slot_glyph(int character, int x_size, int y_size, int margin) {
 ////////////////////////////////////////////////////////////////////
 void DynamicTextPage::
 fill_region(int x, int y, int x_size, int y_size, const LColor &color) {
-  nassertv(x >= 0 && x + x_size <= _x_size && y >= 0 && y + y_size <= _y_size);
+  nassertv(x >= 0 && x + x_size <= _size[0] && y >= 0 && y + y_size <= _size[1]);
   int num_components = get_num_components();
   if (num_components == 1) {
     // Luminance or alpha.
@@ -110,7 +110,7 @@ fill_region(int x, int y, int x_size, int y_size, const LColor &color) {
 
     unsigned char *image = modify_ram_image();
     for (int yi = y; yi < y + y_size; yi++) {
-      unsigned char *row = image + yi * _x_size;
+      unsigned char *row = image + yi * _size[0];
       memset(row + x, v, x_size);
     }
 
@@ -127,7 +127,7 @@ fill_region(int x, int y, int x_size, int y_size, const LColor &color) {
 
     PN_uint16 *image = (PN_uint16 *)modify_ram_image().p();
     for (int yi = y; yi < y + y_size; yi++) {
-      PN_uint16 *row = image + yi * _x_size ;
+      PN_uint16 *row = image + yi * _size[0] ;
       for (int xi = x; xi < x + x_size; xi++) {
         row[xi] = v.v;
       }
@@ -142,7 +142,7 @@ fill_region(int x, int y, int x_size, int y_size, const LColor &color) {
 
     unsigned char *image = modify_ram_image();
     for (int yi = y; yi < y + y_size; yi++) {
-      unsigned char *row = image + yi * _x_size * 3;
+      unsigned char *row = image + yi * _size[0] * 3;
       for (int xi = x; xi < x + x_size; xi++) {
         row[xi * 3] = p0;
         row[xi * 3 + 1] = p1;
@@ -164,12 +164,12 @@ fill_region(int x, int y, int x_size, int y_size, const LColor &color) {
 
     PN_uint32 *image = (PN_uint32 *)modify_ram_image().p();
     for (int yi = y; yi < y + y_size; yi++) {
-      PN_uint32 *row = image + yi * _x_size;
+      PN_uint32 *row = image + yi * _size[0];
       for (int xi = x; xi < x + x_size; xi++) {
         row[xi] = v.v;
       }
     }
-  }    
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -189,7 +189,8 @@ garbage_collect(DynamicTextFont *font) {
   Glyphs::iterator gi;
   for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
     DynamicTextGlyph *glyph = (*gi);
-    if (glyph->_geom_count != 0) {
+    cerr << glyph->get_character() << " - " << glyph->get_ref_count() << "\n";
+    if (glyph->get_ref_count() > 1) {
       // Keep this one.
       new_glyphs.insert(new_glyphs.end(), (*gi));
     } else {
@@ -214,11 +215,11 @@ garbage_collect(DynamicTextFont *font) {
 bool DynamicTextPage::
 find_hole(int &x, int &y, int x_size, int y_size) const {
   y = 0;
-  while (y + y_size <= _y_size) {
-    int next_y = _y_size;
+  while (y + y_size <= _size[1]) {
+    int next_y = _size[1];
     // Scan along the row at 'y'.
     x = 0;
-    while (x + x_size <= _x_size) {
+    while (x + x_size <= _size[0]) {
       int next_x = x;
 
       // Consider the spot at x, y.

+ 4 - 3
panda/src/text/dynamicTextPage.h

@@ -37,10 +37,11 @@ class EXPCL_PANDA_TEXT DynamicTextPage : public Texture {
 public:
   DynamicTextPage(DynamicTextFont *font, int page_number);
 
-  DynamicTextGlyph *slot_glyph(int character, 
-                               int x_size, int y_size, int margin);
+  DynamicTextGlyph *slot_glyph(int character,  int x_size, int y_size,
+                               int margin, PN_stdfloat advance);
 
 PUBLISHED:
+  INLINE const LVecBase2i &get_size() const;
   INLINE int get_x_size() const;
   INLINE int get_y_size() const;
 
@@ -58,7 +59,7 @@ private:
   typedef pvector< PT(DynamicTextGlyph) > Glyphs;
   Glyphs _glyphs;
 
-  int _x_size, _y_size;
+  LVecBase2i _size;
 
   DynamicTextFont *_font;
 

+ 43 - 55
panda/src/text/geomTextGlyph.cxx

@@ -13,9 +13,6 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "geomTextGlyph.h"
-
-#ifdef HAVE_FREETYPE
-
 #include "datagramIterator.h"
 #include "bamReader.h"
 #include "indent.h"
@@ -26,26 +23,25 @@ TypeHandle GeomTextGlyph::_type_handle;
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomTextGlyph::Constructor
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 GeomTextGlyph::
-GeomTextGlyph(DynamicTextGlyph *glyph, const GeomVertexData *data) :
+GeomTextGlyph(const TextGlyph *glyph, const GeomVertexData *data) :
   Geom(data)
 {
   // Initially, there is only one glyph in the Geom.  There might be
   // additional Glyphs later when we flatten the graph and call
   // Geom::unify().
-  if (glyph != (DynamicTextGlyph *)NULL) {
+  if (glyph != (const TextGlyph *)NULL) {
     _glyphs.reserve(1);
     _glyphs.push_back(glyph);
-    glyph->_geom_count++;
   }
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomTextGlyph::Constructor
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 GeomTextGlyph::
 GeomTextGlyph(const GeomVertexData *data) :
@@ -57,59 +53,48 @@ GeomTextGlyph(const GeomVertexData *data) :
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomTextGlyph::Copy Constructor
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 GeomTextGlyph::
 GeomTextGlyph(const GeomTextGlyph &copy) :
   Geom(copy),
   _glyphs(copy._glyphs)
 {
-  Glyphs::iterator gi;
-  for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
-    DynamicTextGlyph *glyph = (*gi);
-    nassertv(glyph != (DynamicTextGlyph *)NULL);
-    glyph->_geom_count++;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomTextGlyph::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+GeomTextGlyph::
+GeomTextGlyph(const Geom &copy, const TextGlyph *glyph) :
+  Geom(copy)
+{
+  if (glyph != (const TextGlyph *)NULL) {
+    _glyphs.reserve(1);
+    _glyphs.push_back(glyph);
   }
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomTextGlyph::Copy Assignment Operator
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 void GeomTextGlyph::
 operator = (const GeomTextGlyph &copy) {
   Geom::operator = (copy);
-  
-  Glyphs::iterator gi;
-  for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
-    DynamicTextGlyph *glyph = (*gi);
-    nassertv(glyph != (DynamicTextGlyph *)NULL);
-    glyph->_geom_count--;
-    nassertv((*gi)->_geom_count >= 0);
-  }
   _glyphs = copy._glyphs;
-  for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
-    DynamicTextGlyph *glyph = (*gi);
-    nassertv(glyph != (DynamicTextGlyph *)NULL);
-    glyph->_geom_count++;
-  }
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomTextGlyph::Destructor
 //       Access: Public, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 GeomTextGlyph::
 ~GeomTextGlyph() {
-  Glyphs::iterator gi;
-  for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
-    DynamicTextGlyph *glyph = (*gi);
-    nassertv(glyph != (DynamicTextGlyph *)NULL);
-    glyph->_geom_count--;
-    nassertv(glyph->_geom_count >= 0);
-  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -149,11 +134,8 @@ copy_primitives_from(const Geom *other) {
   DCAST_INTO_R(tother, other, false);
 
   // Also copy the glyph pointers.
-  Glyphs::const_iterator gi;
-  for (gi = tother->_glyphs.begin(); gi != tother->_glyphs.end(); ++gi) {
-    _glyphs.push_back(*gi);
-    (*gi)->_geom_count++;
-  }
+  _glyphs.reserve(_glyphs.size() + tother->_glyphs.size());
+  _glyphs.insert(_glyphs.end(), tother->_glyphs.begin(), tother->_glyphs.end());
 
   return true;
 }
@@ -176,18 +158,15 @@ count_geom(const Geom *other) {
     const GeomTextGlyph *tother;
     DCAST_INTO_V(tother, other);
     
-    Glyphs::const_iterator gi;
-    for (gi = tother->_glyphs.begin(); gi != tother->_glyphs.end(); ++gi) {
-      _glyphs.push_back(*gi);
-      (*gi)->_geom_count++;
-    }
+    _glyphs.reserve(_glyphs.size() + tother->_glyphs.size());
+    _glyphs.insert(_glyphs.end(), tother->_glyphs.begin(), tother->_glyphs.end());
   }
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomTextGlyph::output
 //       Access: Public, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 void GeomTextGlyph::
 output(ostream &out) const {
@@ -195,8 +174,8 @@ output(ostream &out) const {
   out << ", glyphs: [";
   Glyphs::const_iterator gi;
   for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
-    DynamicTextGlyph *glyph = (*gi);
-    nassertv(glyph != (DynamicTextGlyph *)NULL);
+    const TextGlyph *glyph = (*gi);
+    nassertv(glyph != (const TextGlyph *)NULL);
     out << " " << glyph->get_character();
   }
   out << " ]";
@@ -205,7 +184,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomTextGlyph::write
 //       Access: Public, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 void GeomTextGlyph::
 write(ostream &out, int indent_level) const {
@@ -214,13 +193,24 @@ write(ostream &out, int indent_level) const {
     << "Glyphs: [";
   Glyphs::const_iterator gi;
   for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
-    DynamicTextGlyph *glyph = (*gi);
-    nassertv(glyph != (DynamicTextGlyph *)NULL);
+    const TextGlyph *glyph = (*gi);
+    nassertv(glyph != (const TextGlyph *)NULL);
     out << " " << glyph->get_character();
   }
   out << " ]\n";
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomTextGlyph::add_glyph
+//       Access: Public
+//  Description: Adds a glyph to the list of glyphs referenced by
+//               this Geom.
+////////////////////////////////////////////////////////////////////
+void GeomTextGlyph::
+add_glyph(const TextGlyph *glyph) {
+  _glyphs.push_back(glyph);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomTextGlyph::register_with_factory
 //       Access: Public, Static
@@ -238,7 +228,7 @@ register_with_read_factory() {
 ////////////////////////////////////////////////////////////////////
 TypedWritable* GeomTextGlyph::
 make_GeomTextGlyph(const FactoryParams &params) {
-  GeomTextGlyph *me = new GeomTextGlyph((DynamicTextGlyph *)NULL, 
+  GeomTextGlyph *me = new GeomTextGlyph((const TextGlyph *)NULL,
                                         (GeomVertexData *)NULL);
   DatagramIterator scan;
   BamReader *manager;
@@ -247,5 +237,3 @@ make_GeomTextGlyph(const FactoryParams &params) {
   me->fillin(scan, manager);
   return me;
 }
-
-#endif  // HAVE_FREETYPE

+ 9 - 15
panda/src/text/geomTextGlyph.h

@@ -17,15 +17,12 @@
 
 #include "pandabase.h"
 #include "geom.h"
-
-#ifdef HAVE_FREETYPE
-
-#include "dynamicTextGlyph.h"
+#include "textGlyph.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : GeomTextGlyph
 // Description : This is a specialization on Geom for containing a
-//               primitive intended to represent a DynamicTextGlyph.
+//               primitive intended to represent a TextGlyph.
 //               Its sole purpose is to maintain the geom count on the
 //               glyph, so we can determine the actual usage count on
 //               a dynamic glyph (and thus know when it is safe to
@@ -33,10 +30,10 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_TEXT GeomTextGlyph : public Geom {
 public:
-  GeomTextGlyph(DynamicTextGlyph *glyph,
-                const GeomVertexData *data);
+  GeomTextGlyph(const TextGlyph *glyph, const GeomVertexData *data);
   GeomTextGlyph(const GeomVertexData *data);
   GeomTextGlyph(const GeomTextGlyph &copy);
+  GeomTextGlyph(const Geom &copy, const TextGlyph *glyph);
   void operator = (const GeomTextGlyph &copy);
   virtual ~GeomTextGlyph();
   ALLOC_DELETED_CHAIN(GeomTextGlyph);
@@ -48,8 +45,12 @@ public:
   virtual void output(ostream &out) const;
   virtual void write(ostream &out, int indent_level = 0) const;
 
+  void add_glyph(const TextGlyph *glyph);
+
+  friend class TextAssembler;
+
 private:
-  typedef pvector< PT(DynamicTextGlyph) > Glyphs;
+  typedef pvector< CPT(TextGlyph) > Glyphs;
   Glyphs _glyphs;
 
 public:
@@ -77,11 +78,4 @@ private:
 
 #include "geomTextGlyph.I"
 
-#else  // HAVE_FREETYPE
-
-// Without Freetype, a GeomTextGlyph is really just an ordinary Geom.
-typedef Geom GeomTextGlyph;
-
-#endif  // HAVE_FREETYPE
-
 #endif // GEOMTEXTGLYPH_H

+ 1 - 1
panda/src/text/staticTextFont.cxx

@@ -234,7 +234,7 @@ write(ostream &out, int indent_level) const {
 //               printable glyph.
 ////////////////////////////////////////////////////////////////////
 bool StaticTextFont::
-get_glyph(int character, const TextGlyph *&glyph) {
+get_glyph(int character, CPT(TextGlyph) &glyph) {
   Glyphs::const_iterator gi = _glyphs.find(character);
   if (gi == _glyphs.end()) {
     // No definition for this character.

+ 1 - 1
panda/src/text/staticTextFont.h

@@ -47,7 +47,7 @@ PUBLISHED:
   virtual void write(ostream &out, int indent_level) const;
 
 public:
-  virtual bool get_glyph(int character, const TextGlyph *&glyph);
+  virtual bool get_glyph(int character, CPT(TextGlyph) &glyph);
 
 private:
   void find_character_gsets(PandaNode *root, CPT(Geom) &ch, CPT(Geom) &dot,

+ 0 - 18
panda/src/text/textAssembler.I

@@ -522,24 +522,6 @@ ComputedProperties(ComputedProperties *based_on, const wstring &wname,
       << "Unknown TextProperties: " << name << "\n";
   }
 }
-  
-
-////////////////////////////////////////////////////////////////////
-//     Function: TextAssembler::GlyphPlacement::add_piece
-//       Access: Public
-//  Description: Adds a piece of the glyph, consisting of a single
-//               Geom and an associated RenderState.  Typically, a
-//               glyph will have exactly one piece; there will only be
-//               multiple pieces in the case of cheesy accent marks or
-//               ligatures.
-////////////////////////////////////////////////////////////////////
-INLINE void TextAssembler::GlyphPlacement::
-add_piece(Geom *geom, const RenderState *state) {
-  Piece piece;
-  piece._geom = geom;
-  piece._state = state;
-  _pieces.push_back(piece);
-}
 
 ////////////////////////////////////////////////////////////////////
 //     Function: TextAssembler::GeomCollectorKey::Constructor

File diff suppressed because it is too large
+ 358 - 234
panda/src/text/textAssembler.cxx


+ 41 - 26
panda/src/text/textAssembler.h

@@ -164,12 +164,10 @@ private:
   // And here it is, wordwrapped.
   TextBlock _text_block;
 
-#ifndef CPPPARSER  // interrogate has a bit of trouble with wstring iterators.
   void scan_wtext(TextString &output_string,
                   wstring::const_iterator &si, 
                   const wstring::const_iterator &send,
                   ComputedProperties *current_cprops);
-#endif  // CPPPARSER
 
   bool wordwrap_text();
 
@@ -179,13 +177,6 @@ private:
   // These structures are built up by assemble_paragraph() and
   // assemble_row().  They represent the actual Geoms as laid out in a
   // paragraph.
-  
-  class Piece {
-  public:
-    PT(Geom) _geom;
-    CPT(RenderState) _state;
-  };
-  typedef pvector<Piece> Pieces;
 
   class GeomCollectorKey {
   public:
@@ -218,26 +209,50 @@ private:
   };
   typedef pmap<GeomCollectorKey, GeomCollector> GeomCollectorMap;
 
-  class GlyphPlacement : public MemoryBase {
+  struct QuadDef {
+    // Copying this class is a performance hotspot, hence we define the
+    // move constructor.
+    ALWAYS_INLINE QuadDef() {}
+    ALWAYS_INLINE QuadDef(const QuadDef &copy) :
+      _dimensions(copy._dimensions), _uvs(copy._uvs),
+      _slantl(copy._slantl), _slanth(copy._slanth),
+      _glyph(copy._glyph) {}
+
+#ifdef USE_MOVE_SEMANTICS
+    ALWAYS_INLINE QuadDef(QuadDef &&from) NOEXCEPT :
+      _dimensions(from._dimensions), _uvs(from._uvs),
+      _slantl(from._slantl), _slanth(from._slanth),
+      _glyph(move(from._glyph)) {}
+#endif
+
+    LVecBase4 _dimensions;
+    LVecBase4 _uvs;
+    PN_stdfloat _slantl, _slanth;
+    CPT(TextGlyph) _glyph;
+  };
+  typedef pvector<QuadDef> QuadDefs;
+  typedef pmap<CPT(RenderState), QuadDefs> QuadMap;
+
+  void generate_quads(GeomNode *geom_node, const QuadMap &quad_map);
+
+  class GlyphPlacement {
   public:
-    INLINE void add_piece(Geom *geom, const RenderState *state);
-    void calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
-                           bool &found_any, Thread *current_thread) const;
-    void assign_to(GeomNode *geom_node, const RenderState *state) const;
-    void assign_copy_to(GeomNode *geom_node, const RenderState *state, 
-                        const LMatrix4 &extra_xform) const;
+    void assign_to(GeomNode *geom_node, const RenderState *state,
+                   const LVector2 &offset = LVector2::zero()) const;
 
     void assign_append_to(GeomCollectorMap &geom_collector_map, const RenderState *state,
-                          const LMatrix4 &extra_xform) const;
-    void copy_graphic_to(PandaNode *node, const RenderState *state,
-                         const LMatrix4 &extra_xform) const;
+                          const LVector2 &offset = LVector2::zero()) const;
+    void assign_quad_to(QuadMap &quad_map, const RenderState *state,
+                        const LVector2 &offset = LVector2::zero()) const;
+    void copy_graphic_to(PandaNode *node, const RenderState *state) const;
 
-    Pieces _pieces;
+    CPT(TextGlyph) _glyph;
     PT(PandaNode) _graphic_model;
-    LMatrix4 _xform;
+    PN_stdfloat _xpos, _ypos;
+    PN_stdfloat _scale, _slant;
     const TextProperties *_properties;
   };
-  typedef pvector<GlyphPlacement *> PlacedGlyphs;
+  typedef pvector<GlyphPlacement> PlacedGlyphs;
 
   void assemble_paragraph(PlacedGlyphs &placed_glyphs);
   void assemble_row(TextRow &row,
@@ -281,8 +296,8 @@ private:
 
   static void
   get_character_glyphs(int character, const TextProperties *properties,
-                       bool &got_glyph, const TextGlyph *&glyph,
-                       const TextGlyph *&second_glyph,
+                       bool &got_glyph, CPT(TextGlyph) &glyph,
+                       CPT(TextGlyph) &second_glyph,
                        UnicodeLatinMap::AccentType &accent_type,
                        int &additional_flags,
                        PN_stdfloat &glyph_scale, PN_stdfloat &advance_scale);
@@ -291,13 +306,13 @@ private:
   tack_on_accent(UnicodeLatinMap::AccentType accent_type,
                  const LPoint3 &min_vert, const LPoint3 &max_vert,
                  const LPoint3 &centroid,
-                 const TextProperties *properties, GlyphPlacement *placement) const;
+                 const TextProperties *properties, GlyphPlacement &placement) const;
   bool 
   tack_on_accent(char accent_mark, CheesyPosition position,
                  CheesyTransform transform,
                  const LPoint3 &min_vert, const LPoint3 &max_vert,
                  const LPoint3 &centroid,
-                 const TextProperties *properties, GlyphPlacement *placement) const;
+                 const TextProperties *properties, GlyphPlacement &placement) const;
 
   // These are filled in by assemble_paragraph().
   LVector2 _ul;

+ 2 - 2
panda/src/text/textFont.I

@@ -87,9 +87,9 @@ set_space_advance(PN_stdfloat space_advance) {
 //               it may still return a printable glyph, or it may
 //               return NULL.
 ////////////////////////////////////////////////////////////////////
-INLINE const TextGlyph *TextFont::
+INLINE CPT(TextGlyph) TextFont::
 get_glyph(int character) {
-  const TextGlyph *glyph = NULL;
+  CPT(TextGlyph) glyph;
   get_glyph(character, glyph);
   return glyph;
 }

+ 2 - 2
panda/src/text/textFont.h

@@ -78,12 +78,12 @@ PUBLISHED:
 
   INLINE PN_stdfloat get_space_advance() const;
   INLINE void set_space_advance(PN_stdfloat space_advance);
-  INLINE const TextGlyph *get_glyph(int character);
+  INLINE CPT(TextGlyph) get_glyph(int character);
 
   virtual void write(ostream &out, int indent_level) const;
 
 public:
-  virtual bool get_glyph(int character, const TextGlyph *&glyph)=0;
+  virtual bool get_glyph(int character, CPT(TextGlyph) &glyph)=0;
   TextGlyph *get_invalid_glyph();
 
   static RenderMode string_render_mode(const string &string);

+ 50 - 27
panda/src/text/textGlyph.I

@@ -16,14 +16,15 @@
 ////////////////////////////////////////////////////////////////////
 //     Function: TextGlyph::Default constructor
 //       Access: Public
-//  Description: This constructor makes an invalid glyph.
+//  Description: This constructor makes an empty glyph.
 ////////////////////////////////////////////////////////////////////
 INLINE TextGlyph::
-TextGlyph(int character) :
-  _character(character)
+TextGlyph(int character, PN_stdfloat advance) :
+  _character(character),
+  _geom((Geom *)NULL),
+  _advance(advance),
+  _has_quad(false)
 {
-  _geom = (Geom *)NULL;
-  _advance = 0.0f;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -37,8 +38,12 @@ TextGlyph(int character, const Geom *geom,
   _character(character),
   _geom(geom), 
   _state(state),
-  _advance(advance) 
-{ 
+  _advance(advance),
+  _has_quad(false)
+{
+  if (geom != NULL) {
+    check_quad_geom();
+  }
   if (_state == (RenderState *)NULL) {
     _state = RenderState::make_empty();
   }
@@ -54,8 +59,11 @@ TextGlyph(const TextGlyph &copy) :
   _character(copy._character),
   _geom(copy._geom),
   _state(copy._state),
-  _advance(copy._advance) 
-{ 
+  _advance(copy._advance),
+  _has_quad(copy._has_quad),
+  _quad_dimensions(copy._quad_dimensions),
+  _quad_texcoords(copy._quad_texcoords)
+{
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -69,6 +77,9 @@ operator = (const TextGlyph &copy) {
   _geom = copy._geom;
   _state = copy._state;
   _advance = copy._advance;
+  _has_quad = copy._has_quad;
+  _quad_dimensions = copy._quad_dimensions;
+  _quad_texcoords = copy._quad_texcoords;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -83,28 +94,40 @@ get_character() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: TextGlyph::get_geom
+//     Function: TextGlyph::has_quad
 //       Access: Public
-//  Description: Returns a Geom that renders the particular glyph.
+//  Description: Returns true if this glyph contains the definition
+//               for a simple quad, rather than a more complex piece
+//               of geometry.
+//
+//               You may still call get_geom() even if this returns
+//               true, which will synthesize a Geom for this quad.
 ////////////////////////////////////////////////////////////////////
-INLINE PT(Geom) TextGlyph::
-get_geom(Geom::UsageHint usage_hint) const {
-  if (_geom == (Geom *)NULL) {
-    return NULL;
-  }
+INLINE bool TextGlyph::
+has_quad() const {
+  return _has_quad;
+}
 
-  // We always return a copy of the geom.  That will allow the caller
-  // to modify its vertices without fear of stomping on other copies;
-  // it is also critical for the DynamicTextGlyph, which depends on
-  // this behavior to properly count references to this glyph.
-  PT(Geom) new_geom = _geom->make_copy();
-  new_geom->set_usage_hint(usage_hint);
-  const GeomVertexData *vdata = new_geom->get_vertex_data();
-  nassertr(vdata != NULL, new_geom);
-  if (vdata->get_usage_hint() != usage_hint) {
-    new_geom->modify_vertex_data()->set_usage_hint(usage_hint);
+////////////////////////////////////////////////////////////////////
+//     Function: TextGlyph::get_quad
+//       Access: Public
+//  Description: Assuming that this glyph is representable as a
+//               textured quad, returns its dimensions and UV range.
+//               Returns false if it is not representable as a quad,
+//               or if it is whitespace.
+//
+//               The order of the components is left, bottom,
+//               right, top.
+////////////////////////////////////////////////////////////////////
+INLINE bool TextGlyph::
+get_quad(LVecBase4 &dimensions, LVecBase4 &texcoords) const {
+  if (!_has_quad) {
+    return false;
   }
-  return new_geom;
+
+  dimensions = _quad_dimensions;
+  texcoords = _quad_texcoords;
+  return true;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 274 - 1
panda/src/text/textGlyph.cxx

@@ -27,7 +27,7 @@ TextGlyph::
 
 ////////////////////////////////////////////////////////////////////
 //     Function: TextGlyph::is_whitespace
-//       Access: Public, Virtual
+//       Access: Published, Virtual
 //  Description: Returns true if this glyph represents invisible
 //               whitespace, or false if it corresponds to some
 //               visible character.
@@ -38,3 +38,276 @@ is_whitespace() const {
   // all glyphs are non-whitespace.
   return false;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextGlyph::get_geom
+//       Access: Published
+//  Description: Returns a Geom that renders the particular glyph.
+//               It will be generated if necessary.
+//
+//               This method will always return a copy of the Geom,
+//               so the caller is free to modify it.
+////////////////////////////////////////////////////////////////////
+PT(Geom) TextGlyph::
+get_geom(Geom::UsageHint usage_hint) const {
+  if (_geom.is_null()) {
+    // Maybe we have yet to generate a suitable Geom.
+    if (_has_quad) {
+      ((TextGlyph *)this)->make_quad_geom();
+      if (_geom.is_null()) {
+        return (Geom *)NULL;
+      }
+    } else {
+      // Nope.
+      return (Geom *)NULL;
+    }
+  }
+
+  // We always return a copy of the geom.  That will allow the caller
+  // to modify its vertices without fear of stomping on other copies.
+  // It is also important that we store a reference to this glyph on
+  // the Geom, since the DynamicTextFont relies on counting references
+  // to determine whether a glyph is no longer used.
+  PT(Geom) new_geom = new GeomTextGlyph(*_geom, this);
+  new_geom->set_usage_hint(usage_hint);
+  const GeomVertexData *vdata = new_geom->get_vertex_data();
+  nassertr(vdata != NULL, new_geom);
+  if (vdata->get_usage_hint() != usage_hint) {
+    new_geom->modify_vertex_data()->set_usage_hint(usage_hint);
+  }
+  return new_geom;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextGlyph::calc_tight_bounds
+//       Access: Public
+//  Description: Expands min_point and max_point to include all of the
+//               vertices in the glyph, if any.  found_any is set
+//               true if any points are found.  It is the caller's
+//               responsibility to initialize min_point, max_point,
+//               and found_any before calling this function.
+////////////////////////////////////////////////////////////////////
+void TextGlyph::
+calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
+                  bool &found_any, Thread *current_thread) const {
+  if (_has_quad) {
+    found_any = true;
+    min_point.set(_quad_dimensions[0], 0, _quad_dimensions[1]);
+    max_point.set(_quad_dimensions[2], 0, _quad_dimensions[3]);
+
+  } else if (!_geom.is_null()) {
+    _geom->calc_tight_bounds(min_point, max_point, found_any, current_thread);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextGlyph::set_quad
+//       Access: Public
+//  Description: Sets the glyph using the given quad parameters.
+//               Any Geom assigned will be cleared.
+//               The order of the components is left, bottom,
+//               right, top.
+////////////////////////////////////////////////////////////////////
+void TextGlyph::
+set_quad(const LVecBase4 &dimensions, const LVecBase4 &texcoords,
+         const RenderState *state) {
+  _geom.clear();
+
+  _quad_dimensions = dimensions;
+  _quad_texcoords = texcoords;
+  _has_quad = true;
+  _state = state;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextGlyph::set_geom
+//       Access: Public
+//  Description: Sets the geom from a pre-built Geom object.
+//               Any quad parameters assigned will be cleared.
+////////////////////////////////////////////////////////////////////
+void TextGlyph::
+set_geom(GeomVertexData *vdata, GeomPrimitive *prim, 
+         const RenderState *state) {
+  PT(Geom) geom = new Geom(vdata);
+  geom->add_primitive(prim);
+  _geom = geom;
+
+  _has_quad = false;
+  _state = state;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextGlyph::check_quad_geom
+//       Access: Private
+//  Description: Checks if the geom that was passed in is actually
+//               a quad, and if so, sets the appropriate quad
+//               parameters.
+//
+//               This is useful when loading static text fonts, so
+//               that they can still benefit from the fast text
+//               assembly that is done for quads.
+////////////////////////////////////////////////////////////////////
+void TextGlyph::
+check_quad_geom() {
+  // Currently it looks for rather specific signs that this glyph
+  // has been generated using egg-mkfont.  For now, this is fine.
+  CPT(GeomVertexData) vdata = _geom->get_vertex_data();
+  if (vdata->get_num_rows() != 4) {
+    return;
+  }
+
+  // Does it appear to have a single primitive with two triangles?
+  if (_geom->get_num_primitives() != 1) {
+    return;
+  }
+  CPT(GeomPrimitive) prim = _geom->get_primitive(0);
+  if (!prim->is_indexed() ||
+      prim->get_primitive_type() != GeomPrimitive::PT_polygons) {
+    return;
+  }
+  if (!prim->is_of_type(GeomTriangles::get_class_type())) {
+    prim = prim->decompose();
+  }
+  if (prim->get_num_vertices() != 6) {
+    return;
+  }
+
+  // Check that it has a vertex column and optionally a texcoord column.
+  CPT(GeomVertexFormat) format = vdata->get_format();
+  if (format->get_num_columns() > 2 ||
+      !format->has_column(InternalName::get_vertex())) {
+    return;
+  }
+  if (format->has_column(InternalName::get_texcoord()) != (format->get_num_columns() == 2)) {
+    // The second column, if there is one, is not a texcoord.
+    return;
+  }
+
+  // Check that the vertices are arranged in a square.
+  GeomVertexReader vertex(vdata, InternalName::get_vertex());
+  LVecBase3 v = vertex.get_data3();
+  if (!IS_NEARLY_ZERO(v[1])) {
+    return;
+  }
+  PN_stdfloat minx = v[0];
+  PN_stdfloat maxx = v[0];
+  PN_stdfloat miny = v[2];
+  PN_stdfloat maxy = v[2];
+
+  for (int i = 0; i < 3; ++i) {
+    v = vertex.get_data3();
+    if (!IS_NEARLY_ZERO(v[1])) {
+      return;
+    }
+    if (!IS_NEARLY_EQUAL(v[0], minx) && !IS_NEARLY_EQUAL(v[0], maxx)) {
+      if (!IS_NEARLY_EQUAL(minx, maxx)) {
+        return;
+      }
+      minx = min(v[0], minx);
+      maxx = max(v[0], maxx);
+    }
+    if (!IS_NEARLY_EQUAL(v[2], miny) && !IS_NEARLY_EQUAL(v[2], maxy)) {
+      if (!IS_NEARLY_EQUAL(miny, maxy)) {
+        return;
+      }
+      miny = min(v[2], miny);
+      maxy = max(v[2], maxy);
+    }
+  }
+
+  PN_stdfloat minu = 0;
+  PN_stdfloat maxu = 0;
+  PN_stdfloat minv = 0;
+  PN_stdfloat maxv = 0;
+
+  // Same for the texcoord data.
+  if (format->has_column(InternalName::get_texcoord())) {
+    GeomVertexReader texcoord(vdata, InternalName::get_texcoord());
+    LVecBase2 tc = texcoord.get_data2();
+    minu = tc[0];
+    maxu = tc[0];
+    minv = tc[1];
+    maxv = tc[1];
+
+    for (int i = 0; i < 3; ++i) {
+      tc = texcoord.get_data2();
+      if (!IS_NEARLY_EQUAL(tc[0], minu) && !IS_NEARLY_EQUAL(tc[0], maxu)) {
+        if (!IS_NEARLY_EQUAL(minu, maxu)) {
+          return;
+        }
+        minu = min(tc[0], minu);
+        maxu = max(tc[0], maxu);
+      }
+      if (!IS_NEARLY_EQUAL(tc[1], minv) && !IS_NEARLY_EQUAL(tc[1], maxv)) {
+        if (!IS_NEARLY_EQUAL(minv, maxv)) {
+          return;
+        }
+        minv = min(tc[1], minv);
+        maxv = max(tc[1], maxv);
+      }
+    }
+  }
+
+  _quad_dimensions.set(minx, miny, maxx, maxy);
+  _quad_texcoords.set(minu, minv, maxu, maxv);
+  _has_quad = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextGlyph::make_quad_geom
+//       Access: Private
+//  Description: Generates a Geom representing this text glyph, if
+//               at all possible.
+////////////////////////////////////////////////////////////////////
+void TextGlyph::
+make_quad_geom() {
+  // The default implementation is to generate a Geom based on the
+  // get_quad() implementation, if any.
+  LVecBase4 dimensions, uvs;
+  if (!get_quad(dimensions, uvs)) {
+    return;
+  }
+
+  // Create a corresponding triangle pair.  We use a pair of indexed
+  // triangles rather than a single triangle strip, to avoid the bad
+  // vertex duplication behavior with lots of two-triangle strips.
+  PT(GeomVertexData) vdata = new GeomVertexData
+    (string(), GeomVertexFormat::get_v3t2(), Geom::UH_static);
+  vdata->unclean_set_num_rows(4);
+
+  PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static);
+
+  {
+    GeomVertexWriter vertex(vdata, InternalName::get_vertex());
+    GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
+
+    PT(GeomVertexArrayData) indices = tris->modify_vertices();
+    indices->unclean_set_num_rows(6);
+
+    GeomVertexWriter index(indices, 0);
+
+    vertex.set_data3(dimensions[0], 0, dimensions[3]);
+    vertex.set_data3(dimensions[0], 0, dimensions[1]);
+    vertex.set_data3(dimensions[2], 0, dimensions[3]);
+    vertex.set_data3(dimensions[2], 0, dimensions[1]);
+
+    texcoord.set_data2(uvs[0], uvs[3]);
+    texcoord.set_data2(uvs[0], uvs[1]);
+    texcoord.set_data2(uvs[2], uvs[3]);
+    texcoord.set_data2(uvs[2], uvs[1]);
+
+    index.set_data1i(0);
+    index.set_data1i(1);
+    index.set_data1i(2);
+    index.set_data1i(2);
+    index.set_data1i(1);
+    index.set_data1i(3);
+  }
+
+  // We create a regular Geom here, not a GeomTextGlyph, since doing so
+  // would create a circular reference.  When the get_geom method makes
+  // a copy, it will add in a pointer to this text glyph.
+  PT(Geom) geom = new Geom(vdata);
+  geom->add_primitive(tris);
+  _geom = geom;
+}

+ 26 - 2
panda/src/text/textGlyph.h

@@ -30,7 +30,7 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_TEXT TextGlyph : public TypedReferenceCount {
 public:
-  INLINE TextGlyph(int character);
+  INLINE TextGlyph(int character, PN_stdfloat advance=0);
   INLINE TextGlyph(int character, const Geom *geom, 
                    const RenderState *state, PN_stdfloat advance);
   INLINE TextGlyph(const TextGlyph &copy);
@@ -39,18 +39,42 @@ public:
 
 PUBLISHED:
   INLINE int get_character() const;
-  INLINE PT(Geom) get_geom(Geom::UsageHint usage_hint) const;
+  INLINE bool has_quad() const;
+  INLINE bool get_quad(LVecBase4 &dimensions, LVecBase4 &texcoords) const;
   INLINE const RenderState *get_state() const;
   INLINE PN_stdfloat get_advance() const;
 
   virtual bool is_whitespace() const;
 
+  PT(Geom) get_geom(Geom::UsageHint usage_hint) const;
+
+public:
+  void calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
+                         bool &found_any, Thread *current_thread) const;
+
+  void set_quad(const LVecBase4 &dimensions, const LVecBase4 &texcoords,
+                const RenderState *state);
+
+  void set_geom(GeomVertexData *vdata, GeomPrimitive *prim,
+                const RenderState *state);
+
+private:
+  void check_quad_geom();
+  void make_quad_geom();
+
 protected:
   int _character;
   CPT(Geom) _geom;
   CPT(RenderState) _state;
   PN_stdfloat _advance;
 
+  bool _has_quad;
+  // top, left, bottom, right
+  LVecBase4 _quad_dimensions;
+  LVecBase4 _quad_texcoords;
+
+  friend class GeomTextGlyph;
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;

Some files were not shown because too many files changed in this diff