Browse Source

fix text glyph caching problem

David Rose 20 years ago
parent
commit
cb2e0c46f0

+ 1 - 1
panda/src/char/character.cxx

@@ -406,7 +406,7 @@ copy_geom(const Geom *source, const Character *from,
     return (Geom *)source;
     return (Geom *)source;
   }
   }
   
   
-  PT(Geom) dest = new Geom(*source);
+  PT(Geom) dest = source->make_copy();
   PT(GeomVertexData) vdata = dest->modify_vertex_data();
   PT(GeomVertexData) vdata = dest->modify_vertex_data();
   
   
   vdata->set_transform_table(redirect_transform_table(vdata->get_transform_table(), joint_map, gjmap));
   vdata->set_transform_table(redirect_transform_table(vdata->get_transform_table(), joint_map, gjmap));

+ 1 - 1
panda/src/display/standardMunger.cxx

@@ -197,7 +197,7 @@ munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data) {
     }
     }
     if ((unsupported_bits & Geom::GR_indexed_bits) != 0) {
     if ((unsupported_bits & Geom::GR_indexed_bits) != 0) {
       // Convert indexed geometry to nonindexed geometry.
       // Convert indexed geometry to nonindexed geometry.
-      PT(Geom) new_geom = new Geom(*geom);
+      PT(Geom) new_geom = geom->make_copy();
       new_geom->make_nonindexed(false);
       new_geom->make_nonindexed(false);
       geom = new_geom;
       geom = new_geom;
     }
     }

+ 1 - 1
panda/src/distort/projectionScreen.cxx

@@ -692,7 +692,7 @@ make_mesh_geom_node(const WorkingNodePath &np, const NodePath &camera,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 PT(Geom) ProjectionScreen::
 PT(Geom) ProjectionScreen::
 make_mesh_geom(const Geom *geom, Lens *lens, LMatrix4f &rel_mat) {
 make_mesh_geom(const Geom *geom, Lens *lens, LMatrix4f &rel_mat) {
-  PT(Geom) new_geom = new Geom(*geom);
+  PT(Geom) new_geom = geom->make_copy();
 
 
   GeomVertexRewriter vertex(new_geom->modify_vertex_data(), 
   GeomVertexRewriter vertex(new_geom->modify_vertex_data(), 
                               InternalName::get_vertex());
                               InternalName::get_vertex());

+ 25 - 7
panda/src/gobj/geom.cxx

@@ -41,8 +41,8 @@ Geom(const GeomVertexData *data) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Geom::Copy Constructor
 //     Function: Geom::Copy Constructor
-//       Access: Published
-//  Description: 
+//       Access: Protected
+//  Description: Use make_copy() to duplicate a Geom.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 Geom::
 Geom::
 Geom(const Geom &copy) :
 Geom(const Geom &copy) :
@@ -94,6 +94,19 @@ Geom::
   release_all();
   release_all();
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Geom::make_copy
+//       Access: Public, Virtual
+//  Description: Returns a newly-allocated Geom that is a shallow copy
+//               of this one.  It will be a different Geom pointer,
+//               but its internal data may or may not be shared with
+//               that of the original Geom.
+////////////////////////////////////////////////////////////////////
+Geom *Geom::
+make_copy() const {
+  return new Geom(*this);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Geom::set_usage_hint
 //     Function: Geom::set_usage_hint
 //       Access: Published
 //       Access: Published
@@ -510,12 +523,14 @@ unify_in_place() {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Geom::copy_primitives_from
 //     Function: Geom::copy_primitives_from
-//       Access: Published
+//       Access: Published, Virtual
 //  Description: Copies the primitives from the indicated Geom into
 //  Description: Copies the primitives from the indicated Geom into
 //               this one.  This does require that both Geoms contain
 //               this one.  This does require that both Geoms contain
 //               the same fundamental type primitives, both have a
 //               the same fundamental type primitives, both have a
 //               compatible shade model, and both use the same
 //               compatible shade model, and both use the same
-//               GeomVertexData.
+//               GeomVertexData.  Both Geoms must also be the same
+//               specific class type (i.e. if one is a GeomTextGlyph,
+//               they both must be.)
 //
 //
 //               Returns true if the copy is successful, or false
 //               Returns true if the copy is successful, or false
 //               otherwise (because the Geoms were mismatched).
 //               otherwise (because the Geoms were mismatched).
@@ -529,6 +544,9 @@ copy_primitives_from(const Geom *other) {
   if (get_vertex_data() != other->get_vertex_data()) {
   if (get_vertex_data() != other->get_vertex_data()) {
     return false;
     return false;
   }
   }
+  if (get_type() != other->get_type()) {
+    return false;
+  }
 
 
   ShadeModel this_shade_model = get_shade_model();
   ShadeModel this_shade_model = get_shade_model();
   ShadeModel other_shade_model = other->get_shade_model();
   ShadeModel other_shade_model = other->get_shade_model();
@@ -636,7 +654,7 @@ check_valid() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Geom::output
 //     Function: Geom::output
-//       Access: Published
+//       Access: Published, Virtual
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void Geom::
 void Geom::
@@ -654,7 +672,7 @@ output(ostream &out) const {
     types.insert((*pi)->get_type());
     types.insert((*pi)->get_type());
   }
   }
 
 
-  out << "Geom [";
+  out << get_type() << " [";
   pset<TypeHandle>::iterator ti;
   pset<TypeHandle>::iterator ti;
   for (ti = types.begin(); ti != types.end(); ++ti) {
   for (ti = types.begin(); ti != types.end(); ++ti) {
     out << " " << (*ti);
     out << " " << (*ti);
@@ -664,7 +682,7 @@ output(ostream &out) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Geom::write
 //     Function: Geom::write
-//       Access: Published
+//       Access: Published, Virtual
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void Geom::
 void Geom::

+ 7 - 3
panda/src/gobj/geom.h

@@ -54,10 +54,14 @@ class PreparedGraphicsObjects;
 class EXPCL_PANDA Geom : public TypedWritableReferenceCount, public BoundedObject, public GeomEnums {
 class EXPCL_PANDA Geom : public TypedWritableReferenceCount, public BoundedObject, public GeomEnums {
 PUBLISHED:
 PUBLISHED:
   Geom(const GeomVertexData *data);
   Geom(const GeomVertexData *data);
+protected:
   Geom(const Geom &copy);
   Geom(const Geom &copy);
+PUBLISHED:
   void operator = (const Geom &copy);
   void operator = (const Geom &copy);
   virtual ~Geom();
   virtual ~Geom();
 
 
+  virtual Geom *make_copy() const;
+
   INLINE PrimitiveType get_primitive_type() const;
   INLINE PrimitiveType get_primitive_type() const;
   INLINE ShadeModel get_shade_model() const;
   INLINE ShadeModel get_shade_model() const;
   INLINE int get_geom_rendering() const;
   INLINE int get_geom_rendering() const;
@@ -87,7 +91,7 @@ PUBLISHED:
   void rotate_in_place();
   void rotate_in_place();
   void unify_in_place();
   void unify_in_place();
 
 
-  bool copy_primitives_from(const Geom *other);
+  virtual bool copy_primitives_from(const Geom *other);
 
 
   int get_num_bytes() const;
   int get_num_bytes() const;
   INLINE UpdateSeq get_modified() const;
   INLINE UpdateSeq get_modified() const;
@@ -98,8 +102,8 @@ PUBLISHED:
   // Temporarily virtual.
   // Temporarily virtual.
   virtual bool check_valid() const;
   virtual bool check_valid() const;
 
 
-  void output(ostream &out) const;
-  void write(ostream &out, int indent_level = 0) const;
+  virtual void output(ostream &out) const;
+  virtual void write(ostream &out, int indent_level = 0) const;
 
 
   void clear_cache();
   void clear_cache();
 
 

+ 12 - 4
panda/src/gobj/texture.h

@@ -76,19 +76,27 @@ PUBLISHED:
     F_blue,
     F_blue,
     F_alpha,
     F_alpha,
     F_rgb,     // any suitable RGB mode, whatever the hardware prefers
     F_rgb,     // any suitable RGB mode, whatever the hardware prefers
-    F_rgb5,    // specifically, 5 bits per R,G,B channel.  
-               // this is paired with T_unsigned_byte.  really T_unsigned_byte
-               // should not be specified for this one, it should use
-               // T_unsigned_5bits or something
+
+    // The following request a particular number of bits for the GSG's
+    // internal_format (as stored in the framebuffer), but this
+    // request is not related to the pixel storage within the Texture
+    // object itself, which is always get_num_components() *
+    // get_component_width().
+    F_rgb5,    // 5 bits per R,G,B channel
     F_rgb8,    // 8 bits per R,G,B channel
     F_rgb8,    // 8 bits per R,G,B channel
     F_rgb12,   // 12 bits per R,G,B channel
     F_rgb12,   // 12 bits per R,G,B channel
     F_rgb332,  // 3 bits per R & G, 2 bits for B
     F_rgb332,  // 3 bits per R & G, 2 bits for B
+
     F_rgba,    // any suitable RGBA mode, whatever the hardware prefers
     F_rgba,    // any suitable RGBA mode, whatever the hardware prefers
+
+    // Again, the following bitdepth requests are only for the GSG;
+    // within the Texture object itself, these are all equivalent.
     F_rgbm,    // as above, but only requires 1 bit for alpha (i.e. mask)
     F_rgbm,    // as above, but only requires 1 bit for alpha (i.e. mask)
     F_rgba4,   // 4 bits per R,G,B,A channel
     F_rgba4,   // 4 bits per R,G,B,A channel
     F_rgba5,   // 5 bits per R,G,B channel, 1 bit alpha
     F_rgba5,   // 5 bits per R,G,B channel, 1 bit alpha
     F_rgba8,   // 8 bits per R,G,B,A channel
     F_rgba8,   // 8 bits per R,G,B,A channel
     F_rgba12,  // 12 bits per R,G,B,A channel
     F_rgba12,  // 12 bits per R,G,B,A channel
+
     F_luminance,
     F_luminance,
     F_luminance_alpha,      // 8 bits luminance, 8 bits alpha
     F_luminance_alpha,      // 8 bits luminance, 8 bits alpha
     F_luminance_alphamask   // 8 bits luminance, only needs 1 bit of alpha
     F_luminance_alphamask   // 8 bits luminance, only needs 1 bit of alpha

+ 2 - 2
panda/src/grutil/multitexReducer.cxx

@@ -554,7 +554,7 @@ determine_uv_range(TexCoordf &min_uv, TexCoordf &max_uv,
     const GeomInfo &geom_info = (*gi);
     const GeomInfo &geom_info = (*gi);
     
     
     PT(Geom) geom = 
     PT(Geom) geom = 
-      new Geom(*geom_info._geom_node->get_geom(geom_info._index));
+      geom_info._geom_node->get_geom(geom_info._index)->make_copy();
 
 
     CPT(GeomVertexData) vdata = geom->get_vertex_data();
     CPT(GeomVertexData) vdata = geom->get_vertex_data();
     CPT(GeomVertexFormat) format = vdata->get_format();
     CPT(GeomVertexFormat) format = vdata->get_format();
@@ -811,7 +811,7 @@ transfer_geom(GeomNode *geom_node, const InternalName *texcoord_name,
 
 
     // Copy the Geom.  This actually performs just a pointer copy of
     // Copy the Geom.  This actually performs just a pointer copy of
     // the original GeomVertexData and other associated structures.
     // the original GeomVertexData and other associated structures.
-    PT(Geom) geom = new Geom(*orig_geom);
+    PT(Geom) geom = orig_geom->make_copy();
 
 
     // Ensure that any vertex animation has been applied.
     // Ensure that any vertex animation has been applied.
     geom->set_vertex_data(geom->get_vertex_data()->animate_vertices());
     geom->set_vertex_data(geom->get_vertex_data()->animate_vertices());

+ 1 - 1
panda/src/pgraph/geomNode.I

@@ -92,7 +92,7 @@ modify_geom(int n) {
   nassertr(n >= 0 && n < (int)cdata->_geoms.size(), NULL);
   nassertr(n >= 0 && n < (int)cdata->_geoms.size(), NULL);
   Geom *geom = cdata->_geoms[n]._geom;
   Geom *geom = cdata->_geoms[n]._geom;
   if (geom->get_ref_count() > 1) {
   if (geom->get_ref_count() > 1) {
-    geom = cdata->_geoms[n]._geom = new Geom(*geom);
+    geom = cdata->_geoms[n]._geom = geom->make_copy();
   }
   }
 
 
   return geom;
   return geom;

+ 1 - 1
panda/src/pgraph/geomNode.cxx

@@ -194,7 +194,7 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types,
   GeomNode::Geoms::iterator gi;
   GeomNode::Geoms::iterator gi;
   for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
   for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
     GeomEntry &entry = (*gi);
     GeomEntry &entry = (*gi);
-    PT(Geom) new_geom = new Geom(*entry._geom);
+    PT(Geom) new_geom = entry._geom->make_copy();
 
 
     AccumulatedAttribs geom_attribs = attribs;
     AccumulatedAttribs geom_attribs = attribs;
     entry._state = geom_attribs.collect(entry._state, attrib_types);
     entry._state = geom_attribs.collect(entry._state, attrib_types);

+ 5 - 5
panda/src/pgraph/geomTransformer.cxx

@@ -131,7 +131,7 @@ transform_vertices(GeomNode *node, const LMatrix4f &mat) {
   GeomNode::Geoms::iterator gi;
   GeomNode::Geoms::iterator gi;
   for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
   for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
     GeomNode::GeomEntry &entry = (*gi);
     GeomNode::GeomEntry &entry = (*gi);
-    PT(Geom) new_geom = new Geom(*entry._geom);
+    PT(Geom) new_geom = entry._geom->make_copy();
     if (transform_vertices(new_geom, mat)) {
     if (transform_vertices(new_geom, mat)) {
       node->mark_bound_stale();
       node->mark_bound_stale();
       entry._geom = new_geom;
       entry._geom = new_geom;
@@ -219,7 +219,7 @@ transform_texcoords(GeomNode *node, const InternalName *from_name,
   GeomNode::Geoms::iterator gi;
   GeomNode::Geoms::iterator gi;
   for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
   for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
     GeomNode::GeomEntry &entry = (*gi);
     GeomNode::GeomEntry &entry = (*gi);
-    PT(Geom) new_geom = new Geom(*entry._geom);
+    PT(Geom) new_geom = entry._geom->make_copy();
     if (transform_texcoords(new_geom, from_name, to_name, mat)) {
     if (transform_texcoords(new_geom, from_name, to_name, mat)) {
       entry._geom = new_geom;
       entry._geom = new_geom;
       any_changed = true;
       any_changed = true;
@@ -278,7 +278,7 @@ set_color(GeomNode *node, const Colorf &color) {
   GeomNode::Geoms::iterator gi;
   GeomNode::Geoms::iterator gi;
   for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
   for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
     GeomNode::GeomEntry &entry = (*gi);
     GeomNode::GeomEntry &entry = (*gi);
-    PT(Geom) new_geom = new Geom(*entry._geom);
+    PT(Geom) new_geom = entry._geom->make_copy();
     if (set_color(new_geom, color)) {
     if (set_color(new_geom, color)) {
       entry._geom = new_geom;
       entry._geom = new_geom;
       any_changed = true;
       any_changed = true;
@@ -340,7 +340,7 @@ transform_colors(GeomNode *node, const LVecBase4f &scale) {
   GeomNode::Geoms::iterator gi;
   GeomNode::Geoms::iterator gi;
   for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
   for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
     GeomNode::GeomEntry &entry = (*gi);
     GeomNode::GeomEntry &entry = (*gi);
-    PT(Geom) new_geom = new Geom(*entry._geom);
+    PT(Geom) new_geom = entry._geom->make_copy();
     if (transform_colors(new_geom, scale)) {
     if (transform_colors(new_geom, scale)) {
       entry._geom = new_geom;
       entry._geom = new_geom;
       any_changed = true;
       any_changed = true;
@@ -613,7 +613,7 @@ collect_vertex_data(GeomNode *node, int collect_bits) {
   GeomNode::Geoms::iterator gi;
   GeomNode::Geoms::iterator gi;
   for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
   for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
     GeomNode::GeomEntry &entry = (*gi);
     GeomNode::GeomEntry &entry = (*gi);
-    PT(Geom) new_geom = new Geom(*entry._geom);
+    PT(Geom) new_geom = entry._geom->make_copy();
     entry._geom = new_geom;
     entry._geom = new_geom;
 
 
     if ((collect_bits & SceneGraphReducer::CVD_avoid_dynamic) != 0 &&
     if ((collect_bits & SceneGraphReducer::CVD_avoid_dynamic) != 0 &&

+ 80 - 49
panda/src/text/config_text.cxx

@@ -39,68 +39,93 @@ ConfigureFn(config_text) {
 }
 }
 
 
 ConfigVariableBool text_flatten
 ConfigVariableBool text_flatten
-("text-flatten", true);
-
-ConfigVariableBool text_update_cleared_glyphs
-("text-update-cleared-glyphs", false);
+("text-flatten", true,
+ PRC_DESC("Set this true to flatten text when it is generated, or false to "
+	  "keep it as a deep hierarchy.  Unless you are debugging the text "
+	  "interface, it is almost always a good idea to leave this at "
+	  "its default, true."));
 
 
 ConfigVariableInt text_anisotropic_degree
 ConfigVariableInt text_anisotropic_degree
-("text-anisotropic-degree", 1);
+("text-anisotropic-degree", 1,
+ PRC_DESC("This is the default anisotropic-degree that is set on dynamic "
+	  "font textures.  Setting this to a value greater than 1 can help "
+	  "smooth out the antialiasing for small letters."));
 
 
 ConfigVariableInt text_texture_margin
 ConfigVariableInt text_texture_margin
-("text-texture-margin", 2);
+("text-texture-margin", 2,
+ PRC_DESC("This is the number of texels of empty space reserved around each "
+	  "glyph in the texture.  Setting this value larger will decrease "
+	  "the tendency for adjacent glyphs to bleed into each other at "
+	  "small sizes, but it will increase amount of wasted texture "
+	  "memory."));
 
 
 ConfigVariableDouble text_poly_margin
 ConfigVariableDouble text_poly_margin
-("text-poly-margin", 0.0f);
-
-ConfigVariableInt text_page_x_size
-("text-page-x-size", 256);
-
-ConfigVariableInt text_page_y_size
-("text-page-y-size", 256);
+("text-poly-margin", 0.0f,
+ PRC_DESC("This is the amount by which to make each glyph polygon larger "
+	  "than strictly necessary, in screen units that are added to each "
+	  "margin.  Increasing this value will decrease the tendency for "
+	  "letters to get chopped off at the edges, but it will also "
+	  "increase the tendency for adjacent glyphs to bleed into each "
+	  "other (unless you also increase text-texture-margin)."));
+
+ConfigVariableInt text_page_size
+("text-page-size", "256 256",
+ PRC_DESC("This is the default size for new textures created for dynamic "
+	  "fonts."));
 
 
 ConfigVariableBool text_small_caps
 ConfigVariableBool text_small_caps
-("text-small-caps", false);
+("text-small-caps", false,
+ PRC_DESC("This controls the default setting for "
+	  "TextNode::set_small_caps()."));
 
 
 ConfigVariableDouble text_small_caps_scale
 ConfigVariableDouble text_small_caps_scale
-("text-small-caps-scale", 0.8f);
+("text-small-caps-scale", 0.8f,
+ PRC_DESC("This controls the default setting for "
+	  "TextNode::set_small_caps_scale()."));
 
 
 ConfigVariableFilename text_default_font
 ConfigVariableFilename text_default_font
-("text-default-font", "");
+("text-default-font", "",
+ PRC_DESC("This names a filename that will be loaded at startup time as "
+	  "the default font for any TextNode that does not specify a font "
+	  "otherwise.  The default is to use a special font that is "
+	  "compiled into Panda, if available."));
 
 
 ConfigVariableDouble text_tab_width
 ConfigVariableDouble text_tab_width
-("text-tab-width", 5.0f);
+("text-tab-width", 5.0f,
+ PRC_DESC("This controls the default setting for "
+	  "TextNode::set_tab_width()."));
 
 
-
-// This is the decimal character number that, embedded in a string, is
-// used to bracket the name of a TextProperties structure added to the
-// TextPropertiesManager object, to control the appearance of
-// subsequent text.
 ConfigVariableInt text_push_properties_key
 ConfigVariableInt text_push_properties_key
-("text-push-properties-key", 1);
+("text-push-properties-key", 1,
+ PRC_DESC("This is the decimal character number that, embedded in "
+	  "a string, is used to bracket the name of a TextProperties "
+	  "structure added to the TextPropertiesManager object, to "
+	  "control the appearance of subsequent text."));
 
 
-// This is the decimal character number that undoes the effect of a
-// previous appearance of text_push_properties_key.
 ConfigVariableInt text_pop_properties_key
 ConfigVariableInt text_pop_properties_key
-("text-pop-properties-key", 2);
+("text-pop-properties-key", 2,
+ PRC_DESC("This is the decimal character number that undoes the "
+	  "effect of a previous appearance of text_push_properties_key."));
 
 
-// This is the decimal character number that, embedded in a string, is
-// identified as the soft-hyphen character.
 ConfigVariableInt text_soft_hyphen_key
 ConfigVariableInt text_soft_hyphen_key
-("text-soft-hyphen-key", 3);
+("text-soft-hyphen-key", 3,
+ PRC_DESC("This is the decimal character number that, embedded in a "
+	  "string, is identified as the soft-hyphen character."));
 
 
-// This is similar to the soft-hyphen key, above, except that when it
-// is used as a break point, no character is introduced in its place.
 ConfigVariableInt text_soft_break_key
 ConfigVariableInt text_soft_break_key
-("text-soft-break-key", 4);
+("text-soft-break-key", 4,
+ PRC_DESC("This is similar to text-soft-hyphen-key, except that "
+	  "when it is used as a break point, no character is "
+	  "introduced in its place."));
 
 
-// This is the string that is output, encoded in the default encoding,
-// to represent the hyphen character that is introduced when the line
-// is broken at a soft-hyphen key.
 wstring
 wstring
 get_text_soft_hyphen_output() {
 get_text_soft_hyphen_output() {
   static wstring *text_soft_hyphen_output = NULL;
   static wstring *text_soft_hyphen_output = NULL;
-  static ConfigVariableString cv("text-soft-hyphen-output", "-");
+  static ConfigVariableString 
+    cv("text-soft-hyphen-output", "-",
+       PRC_DESC("This is the string that is output, encoded in the default "
+		"encoding, to represent the hyphen character that is "
+		"introduced when the line is broken at a soft-hyphen key."));
 
 
   if (text_soft_hyphen_output == NULL) {
   if (text_soft_hyphen_output == NULL) {
     TextEncoder encoder;
     TextEncoder encoder;
@@ -110,18 +135,21 @@ get_text_soft_hyphen_output() {
   return *text_soft_hyphen_output;
   return *text_soft_hyphen_output;
 }
 }
 
 
-// If the rightmost whitespace character falls before this fraction of
-// the line, hyphenate a word to the right of that if possible.
 ConfigVariableDouble text_hyphen_ratio
 ConfigVariableDouble text_hyphen_ratio
-("text-hyphen-ratio", 0.7);
+("text-hyphen-ratio", 0.7,
+ PRC_DESC("If the rightmost whitespace character falls before this "
+	  "fraction of the line, hyphenate a word to the right of that "
+	  "if possible."));
 
 
-// This string represents a list of individual characters that should
-// never appear at the beginning of a line following a forced break.
-// Typically these will be punctuation characters.
 wstring
 wstring
 get_text_never_break_before() {
 get_text_never_break_before() {
   static wstring *text_never_break_before = NULL;
   static wstring *text_never_break_before = NULL;
-  static ConfigVariableString cv("text-never-break-before", ",.-:?!;");
+  static ConfigVariableString 
+    cv("text-never-break-before", ",.-:?!;",
+       PRC_DESC("This string represents a list of individual characters "
+		"that should never appear at the beginning of a line "
+		"following a forced break.  Typically these will be "
+		"punctuation characters."));
 
 
   if (text_never_break_before == NULL) {
   if (text_never_break_before == NULL) {
     TextEncoder encoder;
     TextEncoder encoder;
@@ -131,16 +159,19 @@ get_text_never_break_before() {
   return *text_never_break_before;
   return *text_never_break_before;
 }
 }
 
 
-// Unless we have more than this number of text_never_break_before
-// characters in a row, in which case forget it and break wherever we
-// can.
 ConfigVariableInt text_max_never_break
 ConfigVariableInt text_max_never_break
-("text-max-never-break", 3);
+("text-max-never-break", 3,
+ PRC_DESC("If we have more than this number of text-never-break-before "
+	  "characters in a row, do not treat any of them as special and "
+	  "instead break the line wherever we can."));
 
 
 ConfigVariableEnum<Texture::FilterType> text_minfilter
 ConfigVariableEnum<Texture::FilterType> text_minfilter
-("text-minfilter", Texture::FT_linear_mipmap_linear);
+("text-minfilter", Texture::FT_linear_mipmap_linear,
+ PRC_DESC("The default texture minfilter type for dynamic text fonts"));
 ConfigVariableEnum<Texture::FilterType> text_magfilter
 ConfigVariableEnum<Texture::FilterType> text_magfilter
-("text-magfilter", Texture::FT_linear);
+("text-magfilter", Texture::FT_linear,
+ PRC_DESC("The default texture magfilter type for dynamic text fonts"));
+
 
 
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 1 - 3
panda/src/text/config_text.h

@@ -33,12 +33,10 @@ class DSearchPath;
 NotifyCategoryDecl(text, EXPCL_PANDA, EXPTP_PANDA);
 NotifyCategoryDecl(text, EXPCL_PANDA, EXPTP_PANDA);
 
 
 extern ConfigVariableBool text_flatten;
 extern ConfigVariableBool text_flatten;
-extern ConfigVariableBool text_update_cleared_glyphs;
 extern ConfigVariableInt text_anisotropic_degree;
 extern ConfigVariableInt text_anisotropic_degree;
 extern ConfigVariableInt text_texture_margin;
 extern ConfigVariableInt text_texture_margin;
 extern ConfigVariableDouble text_poly_margin;
 extern ConfigVariableDouble text_poly_margin;
-extern ConfigVariableInt text_page_x_size;
-extern ConfigVariableInt text_page_y_size;
+extern ConfigVariableInt text_page_size;
 extern ConfigVariableBool text_small_caps;
 extern ConfigVariableBool text_small_caps;
 extern ConfigVariableDouble text_small_caps_scale;
 extern ConfigVariableDouble text_small_caps_scale;
 extern ConfigVariableFilename text_default_font;
 extern ConfigVariableFilename text_default_font;

+ 0 - 37
panda/src/text/dynamicTextFont.I

@@ -360,43 +360,6 @@ get_anisotropic_degree() const {
   return _anisotropic_degree;
   return _anisotropic_degree;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: DynamicTextFont::set_update_cleared_glyphs
-//       Access: Published, Static
-//  Description: Sets the flag indicating whether texture memory
-//               should be updated immediately as old glyphs are
-//               removed.  If this is true, texture memory will be
-//               immediately updated when old glyphs are removed from
-//               the pages.  If this is false (the default), texture
-//               memory may not be updated until the page is next
-//               written to, that is, the next time a glyph is
-//               recorded on that page.
-//
-//               Most of the time, there is no reason to set this
-//               true, unless you are debugging the DynamicTextFont
-//               code and want to be able to see exactly what is in
-//               each texture map at any given time.
-//
-//               This is a global flag across all DynamicTextFont
-//               objects.
-////////////////////////////////////////////////////////////////////
-INLINE void DynamicTextFont::
-set_update_cleared_glyphs(bool update_cleared_glyphs) {
-  _update_cleared_glyphs = update_cleared_glyphs;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DynamicTextFont::get_update_cleared_glyphs
-//       Access: Published, Static
-//  Description: Returns the flag indicating whether texture memory
-//               should be updated immediately as old glyphs are
-//               removed.  See set_update_cleared_glyphs().
-////////////////////////////////////////////////////////////////////
-INLINE bool DynamicTextFont::
-get_update_cleared_glyphs() {
-  return _update_cleared_glyphs;
-}
-
 INLINE ostream &
 INLINE ostream &
 operator << (ostream &out, const DynamicTextFont &dtf) {
 operator << (ostream &out, const DynamicTextFont &dtf) {
   return out << dtf.get_name();
   return out << dtf.get_name();

+ 11 - 37
panda/src/text/dynamicTextFont.cxx

@@ -25,8 +25,6 @@
 #include "config_express.h"
 #include "config_express.h"
 #include "virtualFileSystem.h"
 #include "virtualFileSystem.h"
 
 
-bool DynamicTextFont::_update_cleared_glyphs = text_update_cleared_glyphs;
-
 TypeHandle DynamicTextFont::_type_handle;
 TypeHandle DynamicTextFont::_type_handle;
 
 
 
 
@@ -139,28 +137,6 @@ garbage_collect() {
   return removed_count;
   return removed_count;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: DynamicTextFont::update_texture_memory
-//       Access: Published
-//  Description: Marks all of the pages dirty so they will be reloaded
-//               into texture memory.  This is necessary only if
-//               set_update_cleared_glyphs() is false, and some
-//               textures have recently been removed from the pages
-//               (for instance, after a call to garbage_collect()).
-//
-//               Calling this just ensures that what you see when you
-//               apply the texture page to a polygon represents what
-//               is actually stored on the page.
-////////////////////////////////////////////////////////////////////
-void DynamicTextFont::
-update_texture_memory() {
-  Pages::iterator pi;
-  for (pi = _pages.begin(); pi != _pages.end(); ++pi) {
-    DynamicTextPage *page = (*pi);
-    page->mark_dirty(Texture::DF_image);
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DynamicTextFont::clear
 //     Function: DynamicTextFont::clear
 //       Access: Published
 //       Access: Published
@@ -245,7 +221,7 @@ get_glyph(int character, const TextGlyph *&glyph) {
   if (ci != _cache.end()) {
   if (ci != _cache.end()) {
     glyph = (*ci).second;
     glyph = (*ci).second;
   } else {
   } else {
-    DynamicTextGlyph *dynamic_glyph = make_glyph(glyph_index);
+    DynamicTextGlyph *dynamic_glyph = make_glyph(character, glyph_index);
     _cache.insert(Cache::value_type(glyph_index, dynamic_glyph));
     _cache.insert(Cache::value_type(glyph_index, dynamic_glyph));
     glyph = dynamic_glyph;
     glyph = dynamic_glyph;
   }
   }
@@ -263,8 +239,8 @@ void DynamicTextFont::
 initialize() {
 initialize() {
   _texture_margin = text_texture_margin;
   _texture_margin = text_texture_margin;
   _poly_margin = text_poly_margin;
   _poly_margin = text_poly_margin;
-  _page_x_size = text_page_x_size;
-  _page_y_size = text_page_y_size;
+  _page_x_size = text_page_size[0];
+  _page_y_size = text_page_size[1];
 
 
   // We don't necessarily want to use mipmaps, since we don't want to
   // We don't necessarily want to use mipmaps, since we don't want to
   // regenerate those every time the texture changes, but we probably
   // regenerate those every time the texture changes, but we probably
@@ -307,7 +283,7 @@ update_filters() {
 //               glyph cannot be created for some reason.
 //               glyph cannot be created for some reason.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 DynamicTextGlyph *DynamicTextFont::
 DynamicTextGlyph *DynamicTextFont::
-make_glyph(int glyph_index) {
+make_glyph(int character, int glyph_index) {
   if (!load_glyph(glyph_index)) {
   if (!load_glyph(glyph_index)) {
     return (DynamicTextGlyph *)NULL;
     return (DynamicTextGlyph *)NULL;
   }
   }
@@ -320,7 +296,7 @@ make_glyph(int glyph_index) {
   if (bitmap.width == 0 || bitmap.rows == 0) {
   if (bitmap.width == 0 || bitmap.rows == 0) {
     // If we got an empty bitmap, it's a special case.
     // If we got an empty bitmap, it's a special case.
     PT(DynamicTextGlyph) glyph = 
     PT(DynamicTextGlyph) glyph = 
-      new DynamicTextGlyph(advance / _font_pixels_per_unit);
+      new DynamicTextGlyph(character, advance / _font_pixels_per_unit);
     _empty_glyphs.push_back(glyph);
     _empty_glyphs.push_back(glyph);
     return glyph;
     return glyph;
 
 
@@ -334,7 +310,7 @@ make_glyph(int glyph_index) {
       // If the bitmap produced from the font doesn't require scaling
       // If the bitmap produced from the font doesn't require scaling
       // before it goes to the texture, we can just copy it directly
       // before it goes to the texture, we can just copy it directly
       // into the texture.
       // into the texture.
-      glyph = slot_glyph(bitmap.width, bitmap.rows);
+      glyph = slot_glyph(character, bitmap.width, bitmap.rows);
       copy_bitmap_to_texture(bitmap, glyph);
       copy_bitmap_to_texture(bitmap, glyph);
 
 
     } else {
     } else {
@@ -346,7 +322,7 @@ make_glyph(int glyph_index) {
       int int_y_size = (int)ceil(tex_y_size);
       int int_y_size = (int)ceil(tex_y_size);
       int bmp_x_size = (int)(int_x_size * _scale_factor + 0.5f);
       int bmp_x_size = (int)(int_x_size * _scale_factor + 0.5f);
       int bmp_y_size = (int)(int_y_size * _scale_factor + 0.5f);
       int bmp_y_size = (int)(int_y_size * _scale_factor + 0.5f);
-      glyph = slot_glyph(int_x_size, int_y_size);
+      glyph = slot_glyph(character, int_x_size, int_y_size);
       
       
       PNMImage image(bmp_x_size, bmp_y_size, PNMImage::CT_grayscale);
       PNMImage image(bmp_x_size, bmp_y_size, PNMImage::CT_grayscale);
       copy_bitmap_to_pnmimage(bitmap, image);
       copy_bitmap_to_pnmimage(bitmap, image);
@@ -356,8 +332,6 @@ make_glyph(int glyph_index) {
       copy_pnmimage_to_texture(reduced, glyph);
       copy_pnmimage_to_texture(reduced, glyph);
     }
     }
       
       
-    glyph->_page->mark_dirty(Texture::DF_image);
-    
     glyph->make_geom(slot->bitmap_top, slot->bitmap_left,
     glyph->make_geom(slot->bitmap_top, slot->bitmap_left,
                      advance, _poly_margin,
                      advance, _poly_margin,
                      tex_x_size, tex_y_size,
                      tex_x_size, tex_y_size,
@@ -460,7 +434,7 @@ copy_pnmimage_to_texture(const PNMImage &image, DynamicTextGlyph *glyph) {
 //               filled in yet except with its size.
 //               filled in yet except with its size.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 DynamicTextGlyph *DynamicTextFont::
 DynamicTextGlyph *DynamicTextFont::
-slot_glyph(int x_size, int y_size) {
+slot_glyph(int character, int x_size, int y_size) {
   // Increase the indicated size by the current margin.
   // Increase the indicated size by the current margin.
   x_size += _texture_margin * 2;
   x_size += _texture_margin * 2;
   y_size += _texture_margin * 2;
   y_size += _texture_margin * 2;
@@ -475,7 +449,7 @@ slot_glyph(int x_size, int y_size) {
 
 
     do {
     do {
       DynamicTextPage *page = _pages[pi];
       DynamicTextPage *page = _pages[pi];
-      DynamicTextGlyph *glyph = page->slot_glyph(x_size, y_size, _texture_margin);
+      DynamicTextGlyph *glyph = page->slot_glyph(character, x_size, y_size, _texture_margin);
       if (glyph != (DynamicTextGlyph *)NULL) {
       if (glyph != (DynamicTextGlyph *)NULL) {
         // Once we found a page to hold the glyph, that becomes our
         // Once we found a page to hold the glyph, that becomes our
         // new preferred page.
         // new preferred page.
@@ -499,7 +473,7 @@ slot_glyph(int x_size, int y_size) {
   // glyphs?
   // glyphs?
   if (garbage_collect() != 0) {
   if (garbage_collect() != 0) {
     // Yes, we just freed up some space.  Try once more, recursively.
     // Yes, we just freed up some space.  Try once more, recursively.
-    return slot_glyph(x_size, y_size);
+    return slot_glyph(character, x_size, y_size);
 
 
   } else {
   } else {
     // No good; all recorded glyphs are actually in use.  We need to
     // No good; all recorded glyphs are actually in use.  We need to
@@ -507,7 +481,7 @@ slot_glyph(int x_size, int y_size) {
     _preferred_page = _pages.size();
     _preferred_page = _pages.size();
     PT(DynamicTextPage) page = new DynamicTextPage(this, _preferred_page);
     PT(DynamicTextPage) page = new DynamicTextPage(this, _preferred_page);
     _pages.push_back(page);
     _pages.push_back(page);
-    return page->slot_glyph(x_size, y_size, _texture_margin);
+    return page->slot_glyph(character, x_size, y_size, _texture_margin);
   }
   }
 }
 }
 
 

+ 2 - 7
panda/src/text/dynamicTextFont.h

@@ -84,14 +84,10 @@ PUBLISHED:
   INLINE void set_anisotropic_degree(int anisotropic_degree);
   INLINE void set_anisotropic_degree(int anisotropic_degree);
   INLINE int get_anisotropic_degree() const;
   INLINE int get_anisotropic_degree() const;
 
 
-  INLINE static void set_update_cleared_glyphs(bool update_cleared_glyphs);
-  INLINE static bool get_update_cleared_glyphs();
-
   int get_num_pages() const;
   int get_num_pages() const;
   DynamicTextPage *get_page(int n) const;
   DynamicTextPage *get_page(int n) const;
 
 
   int garbage_collect();
   int garbage_collect();
-  void update_texture_memory();
   void clear();
   void clear();
 
 
   virtual void write(ostream &out, int indent_level) const;
   virtual void write(ostream &out, int indent_level) const;
@@ -102,15 +98,14 @@ public:
 private:
 private:
   void initialize();
   void initialize();
   void update_filters();
   void update_filters();
-  DynamicTextGlyph *make_glyph(int glyph_index);
+  DynamicTextGlyph *make_glyph(int character, int glyph_index);
   void copy_bitmap_to_texture(const FT_Bitmap &bitmap, DynamicTextGlyph *glyph);
   void copy_bitmap_to_texture(const FT_Bitmap &bitmap, DynamicTextGlyph *glyph);
   void copy_pnmimage_to_texture(const PNMImage &image, DynamicTextGlyph *glyph);
   void copy_pnmimage_to_texture(const PNMImage &image, DynamicTextGlyph *glyph);
-  DynamicTextGlyph *slot_glyph(int x_size, int y_size);
+  DynamicTextGlyph *slot_glyph(int character, int x_size, int y_size);
 
 
   int _texture_margin;
   int _texture_margin;
   float _poly_margin;
   float _poly_margin;
   int _page_x_size, _page_y_size;
   int _page_x_size, _page_y_size;
-  static bool _update_cleared_glyphs;
 
 
   Texture::FilterType _minfilter;
   Texture::FilterType _minfilter;
   Texture::FilterType _magfilter;
   Texture::FilterType _magfilter;

+ 9 - 3
panda/src/text/dynamicTextGlyph.I

@@ -24,8 +24,9 @@
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE DynamicTextGlyph::
 INLINE DynamicTextGlyph::
-DynamicTextGlyph(DynamicTextPage *page, int x, int y,
+DynamicTextGlyph(int character, DynamicTextPage *page, int x, int y,
                  int x_size, int y_size, int margin) :
                  int x_size, int y_size, int margin) :
+  TextGlyph(character),
   _page(page),
   _page(page),
   _x(x), _y(y),
   _x(x), _y(y),
   _x_size(x_size), _y_size(y_size),
   _x_size(x_size), _y_size(y_size),
@@ -42,7 +43,8 @@ DynamicTextGlyph(DynamicTextPage *page, int x, int y,
 //               and no Geom.
 //               and no Geom.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE DynamicTextGlyph::
 INLINE DynamicTextGlyph::
-DynamicTextGlyph(float advance) :
+DynamicTextGlyph(int character, float advance) :
+  TextGlyph(character),
   _page((DynamicTextPage *)NULL),
   _page((DynamicTextPage *)NULL),
   _x(0), _y(0),
   _x(0), _y(0),
   _x_size(0), _y_size(0),
   _x_size(0), _y_size(0),
@@ -58,7 +60,10 @@ DynamicTextGlyph(float advance) :
 //  Description: Copying DynamicTextGlyph objects is not allowed.
 //  Description: Copying DynamicTextGlyph objects is not allowed.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE DynamicTextGlyph::
 INLINE DynamicTextGlyph::
-DynamicTextGlyph(const DynamicTextGlyph &) {
+DynamicTextGlyph(const DynamicTextGlyph &) :
+  TextGlyph(0)
+{
+  nassertv(false);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -68,6 +73,7 @@ DynamicTextGlyph(const DynamicTextGlyph &) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void DynamicTextGlyph::
 INLINE void DynamicTextGlyph::
 operator = (const DynamicTextGlyph &) {
 operator = (const DynamicTextGlyph &) {
+  nassertv(false);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

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

@@ -36,9 +36,10 @@ class DynamicTextPage;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA DynamicTextGlyph : public TextGlyph {
 class EXPCL_PANDA DynamicTextGlyph : public TextGlyph {
 public:
 public:
-  INLINE DynamicTextGlyph(DynamicTextPage *page, int x, int y,
-                          int x_size, int y_size, int margin);
-  INLINE DynamicTextGlyph(float advance);
+  INLINE DynamicTextGlyph(int character, DynamicTextPage *page,
+			  int x, int y, int x_size, int y_size, 
+			  int margin);
+  INLINE DynamicTextGlyph(int character, float advance);
 private:
 private:
   INLINE DynamicTextGlyph(const DynamicTextGlyph &copy);
   INLINE DynamicTextGlyph(const DynamicTextGlyph &copy);
   INLINE void operator = (const DynamicTextGlyph &copy);
   INLINE void operator = (const DynamicTextGlyph &copy);

+ 3 - 8
panda/src/text/dynamicTextPage.cxx

@@ -66,7 +66,7 @@ DynamicTextPage(DynamicTextFont *font, int page_number) :
 //               glyph object and returns it; otherwise, returns NULL.
 //               glyph object and returns it; otherwise, returns NULL.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 DynamicTextGlyph *DynamicTextPage::
 DynamicTextGlyph *DynamicTextPage::
-slot_glyph(int x_size, int y_size, int margin) {
+slot_glyph(int character, int x_size, int y_size, int margin) {
   int x, y;
   int x, y;
   if (!find_hole(x, y, x_size, y_size)) {
   if (!find_hole(x, y, x_size, y_size)) {
     // No room for the glyph.
     // No room for the glyph.
@@ -75,7 +75,8 @@ slot_glyph(int x_size, int y_size, int margin) {
 
 
   // The glyph can be fit at (x, y).  Slot it.
   // The glyph can be fit at (x, y).  Slot it.
   PT(DynamicTextGlyph) glyph = 
   PT(DynamicTextGlyph) glyph = 
-    new DynamicTextGlyph(this, x, y, x_size, y_size, margin);
+    new DynamicTextGlyph(character, this,
+			 x, y, x_size, y_size, margin);
   _glyphs.push_back(glyph);
   _glyphs.push_back(glyph);
   return glyph;
   return glyph;
 }
 }
@@ -107,12 +108,6 @@ garbage_collect() {
     }
     }
   }
   }
 
 
-  if (removed_count != 0 && DynamicTextFont::get_update_cleared_glyphs()) {
-    // Only mark the texture dirty if the user specifically requested
-    // an automatic texture memory update upon clearing glyphs.
-    mark_dirty(Texture::DF_image);
-  }
-
   _glyphs.swap(new_glyphs);
   _glyphs.swap(new_glyphs);
   return removed_count;
   return removed_count;
 }
 }

+ 2 - 1
panda/src/text/dynamicTextPage.h

@@ -41,7 +41,8 @@ class EXPCL_PANDA DynamicTextPage : public Texture {
 public:
 public:
   DynamicTextPage(DynamicTextFont *font, int page_number);
   DynamicTextPage(DynamicTextFont *font, int page_number);
 
 
-  DynamicTextGlyph *slot_glyph(int x_size, int y_size, int margin);
+  DynamicTextGlyph *slot_glyph(int character, 
+			       int x_size, int y_size, int margin);
 
 
   INLINE int get_x_size() const;
   INLINE int get_x_size() const;
   INLINE int get_y_size() const;
   INLINE int get_y_size() const;

+ 0 - 30
panda/src/text/geomTextGlyph.I

@@ -16,33 +16,3 @@
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomTextGlyph::Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE GeomTextGlyph::
-GeomTextGlyph(DynamicTextGlyph *glyph, const GeomVertexData *data) :
-  Geom(data),
-  _glyph(glyph)
-{
-  if (_glyph != (DynamicTextGlyph *)NULL) {
-    _glyph->_geom_count++;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomTextGlyph::Copy Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE GeomTextGlyph::
-GeomTextGlyph(const GeomTextGlyph &copy) :
-  Geom(copy),
-  _glyph(copy._glyph)
-{
-  if (_glyph != (DynamicTextGlyph *)NULL) {
-    _glyph->_geom_count++;
-  }
-}

+ 115 - 10
panda/src/text/geomTextGlyph.cxx

@@ -22,10 +22,46 @@
 
 
 #include "datagramIterator.h"
 #include "datagramIterator.h"
 #include "bamReader.h"
 #include "bamReader.h"
+#include "indent.h"
 
 
 TypeHandle GeomTextGlyph::_type_handle;
 TypeHandle GeomTextGlyph::_type_handle;
 
 
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomTextGlyph::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+GeomTextGlyph::
+GeomTextGlyph(DynamicTextGlyph *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().
+  _glyphs.reserve(1);
+  _glyphs.push_back(glyph);
+  if (glyph != (DynamicTextGlyph *)NULL) {
+    glyph->_geom_count++;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomTextGlyph::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+GeomTextGlyph::
+GeomTextGlyph(const GeomTextGlyph &copy) :
+  Geom(copy),
+  _glyphs(copy._glyphs)
+{
+  Glyphs::iterator gi;
+  for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
+    (*gi)->_geom_count++;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomTextGlyph::Copy Assignment Operator
 //     Function: GeomTextGlyph::Copy Assignment Operator
 //       Access: Public
 //       Access: Public
@@ -34,14 +70,15 @@ TypeHandle GeomTextGlyph::_type_handle;
 void GeomTextGlyph::
 void GeomTextGlyph::
 operator = (const GeomTextGlyph &copy) {
 operator = (const GeomTextGlyph &copy) {
   Geom::operator = (copy);
   Geom::operator = (copy);
-  if (_glyph != copy._glyph) {
-    if (_glyph != (DynamicTextGlyph *)NULL) {
-      _glyph->_geom_count--;
-    }
-    _glyph = copy._glyph;
-    if (_glyph != (DynamicTextGlyph *)NULL) {
-      _glyph->_geom_count++;
-    }
+  
+  Glyphs::iterator gi;
+  for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
+    (*gi)->_geom_count--;
+    nassertv((*gi)->_geom_count >= 0);
+  }
+  _glyphs = copy._glyphs;
+  for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
+    (*gi)->_geom_count++;
   }
   }
 }
 }
 
 
@@ -52,8 +89,10 @@ operator = (const GeomTextGlyph &copy) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomTextGlyph::
 GeomTextGlyph::
 ~GeomTextGlyph() {
 ~GeomTextGlyph() {
-  if (_glyph != (DynamicTextGlyph *)NULL) {
-    _glyph->_geom_count--;
+  Glyphs::iterator gi;
+  for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
+    (*gi)->_geom_count--;
+    nassertv((*gi)->_geom_count >= 0);
   }
   }
 }
 }
 
 
@@ -70,6 +109,72 @@ make_copy() const {
   return new GeomTextGlyph(*this);
   return new GeomTextGlyph(*this);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomTextGlyph::copy_primitives_from
+//       Access: Public, Virtual
+//  Description: Copies the primitives from the indicated Geom into
+//               this one.  This does require that both Geoms contain
+//               the same fundamental type primitives, both have a
+//               compatible shade model, and both use the same
+//               GeomVertexData.  Both Geoms must also be the same
+//               specific class type (i.e. if one is a GeomTextGlyph,
+//               they both must be.)
+//
+//               Returns true if the copy is successful, or false
+//               otherwise (because the Geoms were mismatched).
+////////////////////////////////////////////////////////////////////
+bool GeomTextGlyph::
+copy_primitives_from(const Geom *other) {
+  if (!Geom::copy_primitives_from(other)) {
+    return false;
+  }
+
+  const GeomTextGlyph *tother;
+  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++;
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomTextGlyph::output
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void GeomTextGlyph::
+output(ostream &out) const {
+  Geom::output(out);
+  out << ", glyphs: [";
+  Glyphs::const_iterator gi;
+  for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
+    out << " " << (*gi)->get_character();
+  }
+  out << " ]";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomTextGlyph::write
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void GeomTextGlyph::
+write(ostream &out, int indent_level) const {
+  Geom::write(out, indent_level);
+  indent(out, indent_level)
+    << "Glyphs: [";
+  Glyphs::const_iterator gi;
+  for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
+    out << " " << (*gi)->get_character();
+  }
+  out << " ]\n";
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomTextGlyph::register_with_factory
 //     Function: GeomTextGlyph::register_with_factory
 //       Access: Public, Static
 //       Access: Public, Static

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

@@ -37,16 +37,21 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA GeomTextGlyph : public Geom {
 class EXPCL_PANDA GeomTextGlyph : public Geom {
 public:
 public:
-  INLINE GeomTextGlyph(DynamicTextGlyph *glyph,
-		       const GeomVertexData *data);
-  INLINE GeomTextGlyph(const GeomTextGlyph &copy);
+  GeomTextGlyph(DynamicTextGlyph *glyph,
+		const GeomVertexData *data);
+  GeomTextGlyph(const GeomTextGlyph &copy);
   void operator = (const GeomTextGlyph &copy);
   void operator = (const GeomTextGlyph &copy);
   virtual ~GeomTextGlyph();
   virtual ~GeomTextGlyph();
 
 
   virtual Geom *make_copy() const;
   virtual Geom *make_copy() const;
+  virtual bool copy_primitives_from(const Geom *other);
+
+  virtual void output(ostream &out) const;
+  virtual void write(ostream &out, int indent_level = 0) const;
 
 
 private:
 private:
-  PT(DynamicTextGlyph) _glyph;
+  typedef pvector< PT(DynamicTextGlyph) > Glyphs;
+  Glyphs _glyphs;
 
 
 public:
 public:
   static void register_with_read_factory();
   static void register_with_read_factory();

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

@@ -256,7 +256,7 @@ find_characters(PandaNode *root, const RenderState *net_state) {
       GeomVertexReader reader(dot->get_vertex_data(), InternalName::get_vertex());
       GeomVertexReader reader(dot->get_vertex_data(), InternalName::get_vertex());
       float width = reader.get_data1f();
       float width = reader.get_data1f();
 
 
-      _glyphs[character] = new TextGlyph(ch, state, width);
+      _glyphs[character] = new TextGlyph(character, ch, state, width);
     }
     }
 
 
   } else if (name == "ds") {
   } else if (name == "ds") {

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

@@ -1469,7 +1469,7 @@ assign_copy_to(GeomNode *geom_node, const RenderState *state,
   Pieces::const_iterator pi;
   Pieces::const_iterator pi;
   for (pi = _pieces.begin(); pi != _pieces.end(); ++pi) {
   for (pi = _pieces.begin(); pi != _pieces.end(); ++pi) {
     const Geom *geom = (*pi)._geom;
     const Geom *geom = (*pi)._geom;
-    PT(Geom) new_geom = new Geom(*geom);
+    PT(Geom) new_geom = geom->make_copy();
     new_geom->transform_vertices(new_xform);
     new_geom->transform_vertices(new_xform);
     geom_node->add_geom(new_geom, state->compose((*pi)._state));
     geom_node->add_geom(new_geom, state->compose((*pi)._state));
   }
   }

+ 23 - 4
panda/src/text/textGlyph.I

@@ -23,7 +23,9 @@
 //  Description: This constructor makes an invalid glyph.
 //  Description: This constructor makes an invalid glyph.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE TextGlyph::
 INLINE TextGlyph::
-TextGlyph() {
+TextGlyph(int character) :
+  _character(character)
+{
   _geom = (Geom *)NULL;
   _geom = (Geom *)NULL;
   _advance = 0.0f;
   _advance = 0.0f;
 }
 }
@@ -34,8 +36,12 @@ TextGlyph() {
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE TextGlyph::
 INLINE TextGlyph::
-TextGlyph(const Geom *geom, const RenderState *state, float advance) :
-  _geom(geom), _state(state), _advance(advance) 
+TextGlyph(int character, const Geom *geom, 
+	  const RenderState *state, float advance) :
+  _character(character),
+  _geom(geom), 
+  _state(state),
+  _advance(advance) 
 { 
 { 
   if (_state == (RenderState *)NULL) {
   if (_state == (RenderState *)NULL) {
     _state = RenderState::make_empty();
     _state = RenderState::make_empty();
@@ -49,6 +55,7 @@ TextGlyph(const Geom *geom, const RenderState *state, float advance) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE TextGlyph::
 INLINE TextGlyph::
 TextGlyph(const TextGlyph &copy) :
 TextGlyph(const TextGlyph &copy) :
+  _character(copy._character),
   _geom(copy._geom),
   _geom(copy._geom),
   _state(copy._state),
   _state(copy._state),
   _advance(copy._advance) 
   _advance(copy._advance) 
@@ -62,11 +69,23 @@ TextGlyph(const TextGlyph &copy) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void TextGlyph::
 INLINE void TextGlyph::
 operator = (const TextGlyph &copy) {
 operator = (const TextGlyph &copy) {
+  _character = copy._character;
   _geom = copy._geom;
   _geom = copy._geom;
   _state = copy._state;
   _state = copy._state;
   _advance = copy._advance;
   _advance = copy._advance;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: TextGlyph::get_character
+//       Access: Public
+//  Description: Returns the Unicode value that corresponds to the
+//               character this glyph represents.
+////////////////////////////////////////////////////////////////////
+INLINE int TextGlyph::
+get_character() const {
+  return _character;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: TextGlyph::get_geom
 //     Function: TextGlyph::get_geom
 //       Access: Public
 //       Access: Public
@@ -82,7 +101,7 @@ get_geom(Geom::UsageHint usage_hint) const {
   // to modify its vertices without fear of stomping on other copies;
   // to modify its vertices without fear of stomping on other copies;
   // it is also critical for the DynamicTextGlyph, which depends on
   // it is also critical for the DynamicTextGlyph, which depends on
   // this behavior to properly count references to this glyph.
   // this behavior to properly count references to this glyph.
-  PT(Geom) new_geom = new Geom(*_geom);
+  PT(Geom) new_geom = _geom->make_copy();
   new_geom->set_usage_hint(usage_hint);
   new_geom->set_usage_hint(usage_hint);
   if (new_geom->get_vertex_data()->get_usage_hint() != usage_hint) {
   if (new_geom->get_vertex_data()->get_usage_hint() != usage_hint) {
     new_geom->modify_vertex_data()->set_usage_hint(usage_hint);
     new_geom->modify_vertex_data()->set_usage_hint(usage_hint);

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

@@ -34,17 +34,20 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA TextGlyph : public ReferenceCount {
 class EXPCL_PANDA TextGlyph : public ReferenceCount {
 public:
 public:
-  INLINE TextGlyph();
-  INLINE TextGlyph(const Geom *geom, const RenderState *state, float advance);
+  INLINE TextGlyph(int character);
+  INLINE TextGlyph(int character, const Geom *geom, 
+		   const RenderState *state, float advance);
   INLINE TextGlyph(const TextGlyph &copy);
   INLINE TextGlyph(const TextGlyph &copy);
   INLINE void operator = (const TextGlyph &copy);
   INLINE void operator = (const TextGlyph &copy);
   virtual ~TextGlyph();
   virtual ~TextGlyph();
 
 
+  INLINE int get_character() const;
   INLINE PT(Geom) get_geom(Geom::UsageHint usage_hint) const;
   INLINE PT(Geom) get_geom(Geom::UsageHint usage_hint) const;
   INLINE const RenderState *get_state() const;
   INLINE const RenderState *get_state() const;
   INLINE float get_advance() const;
   INLINE float get_advance() const;
 
 
 protected:
 protected:
+  int _character;
   CPT(Geom) _geom;
   CPT(Geom) _geom;
   CPT(RenderState) _state;
   CPT(RenderState) _state;
   float _advance;
   float _advance;

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

@@ -38,7 +38,7 @@ TextProperties::
 TextProperties() {
 TextProperties() {
   _specified = 0;
   _specified = 0;
 
 
-  _small_caps = false;
+  _small_caps = text_small_caps;
   _small_caps_scale = text_small_caps_scale;
   _small_caps_scale = text_small_caps_scale;
   _slant = 0.0f;
   _slant = 0.0f;
   _align = A_left;
   _align = A_left;