From c037a890dd4100dc90b64c08765c6a405d47f34d Mon Sep 17 00:00:00 2001 From: David Rose Date: Mon, 11 Feb 2002 15:07:11 +0000 Subject: [PATCH] refinements to DynamicText --- panda/src/text/dynamicTextFont.I | 108 ++++++++++++++++++++++++++-- panda/src/text/dynamicTextFont.cxx | 106 ++++++++++++++++++--------- panda/src/text/dynamicTextFont.h | 24 +++++-- panda/src/text/dynamicTextGlyph.cxx | 18 ++--- panda/src/text/dynamicTextGlyph.h | 3 +- 5 files changed, 204 insertions(+), 55 deletions(-) diff --git a/panda/src/text/dynamicTextFont.I b/panda/src/text/dynamicTextFont.I index 70e8374e64..54c6309dcc 100644 --- a/panda/src/text/dynamicTextFont.I +++ b/panda/src/text/dynamicTextFont.I @@ -18,7 +18,72 @@ //////////////////////////////////////////////////////////////////// -// Function: DynamicTextFont::set_margin +// Function: DynamicTextFont::set_point_size +// Access: Published +// Description: Sets the point size of the font. This controls the +// apparent size of the font onscreen. By convention, a +// 10 point font is about 1 screen unit high. +// +// This should only be called before any characters have +// been requested out of the font, or immediately after +// calling clear(). +//////////////////////////////////////////////////////////////////// +INLINE bool DynamicTextFont:: +set_point_size(float point_size) { + // If this assertion fails, you didn't call clear() first. RTFM. + nassertr(get_num_pages() == 0, false); + + _point_size = point_size; + return reset_scale(); +} + +//////////////////////////////////////////////////////////////////// +// Function: DynamicTextFont::get_point_size +// Access: Published +// Description: Returns the point size of the font. +//////////////////////////////////////////////////////////////////// +INLINE float DynamicTextFont:: +get_point_size() const { + return _point_size; +} + +//////////////////////////////////////////////////////////////////// +// Function: DynamicTextFont::set_pixels_per_unit +// Access: Published +// Description: Set the resolution of the texture map, and hence the +// clarity of the resulting font. This sets the number +// of pixels in the texture map that are used for each +// onscreen unit. +// +// Setting this number larger results in an easier to +// read font, but at the cost of more texture memory. +// +// This should only be called before any characters have +// been requested out of the font, or immediately after +// calling clear(). +//////////////////////////////////////////////////////////////////// +INLINE bool DynamicTextFont:: +set_pixels_per_unit(float pixels_per_unit) { + // If this assertion fails, you didn't call clear() first. RTFM. + nassertr(get_num_pages() == 0, false); + + _pixels_per_unit = pixels_per_unit; + return reset_scale(); +} + +//////////////////////////////////////////////////////////////////// +// Function: DynamicTextFont::get_pixels_per_unit +// Access: Published +// Description: Returns the resolution of the texture map. See +// set_pixels_per_unit(). +//////////////////////////////////////////////////////////////////// +INLINE float DynamicTextFont:: +get_pixels_per_unit() const { + return _pixels_per_unit; +} + +//////////////////////////////////////////////////////////////////// +// Function: DynamicTextFont::set_texture_margin // Access: Published // Description: Sets the number of pixels of padding that is added // around the border of each glyph before adding it to @@ -26,19 +91,48 @@ // neighboring glyphs in the texture map. //////////////////////////////////////////////////////////////////// INLINE void DynamicTextFont:: -set_margin(int margin) { - _margin = margin; +set_texture_margin(int texture_margin) { + _texture_margin = texture_margin; } //////////////////////////////////////////////////////////////////// -// Function: DynamicTextFont::get_margin +// Function: DynamicTextFont::get_texture_margin // Access: Published // Description: Returns the number of pixels of padding that is added -// around the border of each glyph. See set_margin(). +// around the border of each glyph in the texture map. +// See set_texture_margin(). //////////////////////////////////////////////////////////////////// INLINE int DynamicTextFont:: -get_margin() const { - return _margin; +get_texture_margin() const { + return _texture_margin; +} + +//////////////////////////////////////////////////////////////////// +// Function: DynamicTextFont::set_poly_margin +// Access: Published +// Description: Sets the number of pixels of padding that is included +// around each glyph in the generated polygons. This +// helps prevent the edges of the glyphs from being cut +// off at small minifications. It is not related to the +// amount of extra pixels reserved in the texture map +// (but it should be no larger than this number, which +// is controlled by set_texture_margin()). +//////////////////////////////////////////////////////////////////// +INLINE void DynamicTextFont:: +set_poly_margin(float poly_margin) { + _poly_margin = poly_margin; +} + +//////////////////////////////////////////////////////////////////// +// Function: DynamicTextFont::get_poly_margin +// Access: Published +// Description: Returns the number of pixels of padding that is +// included around each glyph in the generated polygons. +// See set_poly_margin(). +//////////////////////////////////////////////////////////////////// +INLINE float DynamicTextFont:: +get_poly_margin() const { + return _poly_margin; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/text/dynamicTextFont.cxx b/panda/src/text/dynamicTextFont.cxx index 2042cb04f6..e0af9e7f42 100644 --- a/panda/src/text/dynamicTextFont.cxx +++ b/panda/src/text/dynamicTextFont.cxx @@ -43,23 +43,16 @@ static const float points_per_inch = 72.0f; // Description: The constructor expects the name of some font file // that FreeType can read, along with face_index, // indicating which font within the file to load -// (usually 0), the point size of the font, and the -// resolution at which to generate the font. -// -// The choice of point size affects the apparent size of -// the generated characters (as well as the clarity), -// while the pixels_per_unit affects only the clarity. +// (usually 0). //////////////////////////////////////////////////////////////////// DynamicTextFont:: -DynamicTextFont(const Filename &font_filename, int face_index, - float point_size, float pixels_per_unit) { - _margin = 2; +DynamicTextFont(const Filename &font_filename, int face_index) { + _texture_margin = 2; + _poly_margin = 1.0f; _page_x_size = 256; _page_y_size = 256; - _pixels_per_unit = pixels_per_unit; - - float units_per_inch = (points_per_inch / points_per_unit); - int dpi = (int)(_pixels_per_unit * units_per_inch); + _point_size = 10.0f; + _pixels_per_unit = 40.0f; if (!_ft_initialized) { initialize_ft_library(); @@ -90,23 +83,16 @@ DynamicTextFont(const Filename &font_filename, int face_index, } else { string name = _face->family_name; - name += " "; - name += _face->style_name; - - _is_valid = true; + if (_face->style_name != NULL) { + name += " "; + name += _face->style_name; + } set_name(name); text_cat.info() << "Loaded font " << get_name() << "\n"; - - error = FT_Set_Char_Size(_face, - (int)(point_size * 64), (int)(point_size * 64), - dpi, dpi); - if (error) { - text_cat.warning() - << "Unable to set point size of " << get_name() - << " to " << point_size << " at " << dpi << " dots per inch.\n"; - } + _is_valid = true; + reset_scale(); } } } @@ -142,6 +128,25 @@ get_page(int n) const { return _pages[n]; } +//////////////////////////////////////////////////////////////////// +// Function: DynamicTextFont::clear +// Access: Published +// Description: Drops all the glyphs out of the cache and frees any +// association with any previously-generated pages. +// +// Calling this frequently can result in wasted texture +// memory, as any previously rendered text will still +// keep a pointer to the old, previously-generated +// pages. As long as the previously rendered text +// remains around, the old pages will also remain +// around. +//////////////////////////////////////////////////////////////////// +void DynamicTextFont:: +clear() { + _pages.clear(); + _cache.clear(); +} + //////////////////////////////////////////////////////////////////// // Function: DynamicTextFont::write // Access: Published, Virtual @@ -150,7 +155,9 @@ get_page(int n) const { void DynamicTextFont:: write(ostream &out, int indent_level) const { indent(out, indent_level) - << "DynamicTextFont " << get_name() << ".\n"; + << "DynamicTextFont " << get_name() << ", " + << _cache.size() << " glyphs, " + << get_num_pages() << " pages.\n"; } //////////////////////////////////////////////////////////////////// @@ -165,10 +172,45 @@ get_glyph(int character) { if (ci != _cache.end()) { return (*ci).second; } + if (!_is_valid) { + return (TextGlyph *)NULL; + } + DynamicTextGlyph *glyph = make_glyph(character); _cache.insert(Cache::value_type(character, glyph)); return glyph; } + +//////////////////////////////////////////////////////////////////// +// Function: DynamicTextFont::reset_scale +// Access: Private +// Description: Resets the font to use the current _point_size and +// _pixels_per_unit. Returns true if successful, false +// otherwise. +//////////////////////////////////////////////////////////////////// +bool DynamicTextFont:: +reset_scale() { + float units_per_inch = (points_per_inch / points_per_unit); + int dpi = (int)(_pixels_per_unit * units_per_inch); + + int error = FT_Set_Char_Size(_face, + (int)(_point_size * 64), (int)(_point_size * 64), + dpi, dpi); + if (error) { + text_cat.warning() + << "Unable to set " << get_name() + << " to " << _point_size << "pt at " << dpi << " dpi.\n"; + _line_height = 1.0f; + return false; + } + + // The face's height is only relevant for scalable fonts, + // according to FreeType. How should we determine whether we + // have a scalable font or otherwise? + float pixel_size = _point_size * (_pixels_per_unit / points_per_unit); + _line_height = (float)_face->height * pixel_size / ((float)_face->units_per_EM * 64.0f); + return true; +} //////////////////////////////////////////////////////////////////// // Function: DynamicTextFont::make_glyph @@ -217,7 +259,7 @@ make_glyph(int character) { float advance = slot->advance.x / 64.0; glyph->make_geom(slot->bitmap_top, slot->bitmap_left, advance, - _pixels_per_unit); + _poly_margin, _pixels_per_unit); return glyph; } @@ -233,14 +275,14 @@ make_glyph(int character) { DynamicTextGlyph *DynamicTextFont:: slot_glyph(int x_size, int y_size) { // Increase the indicated size by the current margin. - x_size += _margin * 2; - y_size += _margin * 2; + x_size += _texture_margin * 2; + y_size += _texture_margin * 2; Pages::iterator pi; for (pi = _pages.begin(); pi != _pages.end(); ++pi) { DynamicTextPage *page = (*pi); - DynamicTextGlyph *glyph = page->slot_glyph(x_size, y_size, _margin); + DynamicTextGlyph *glyph = page->slot_glyph(x_size, y_size, _texture_margin); if (glyph != (DynamicTextGlyph *)NULL) { return glyph; } @@ -257,7 +299,7 @@ slot_glyph(int x_size, int y_size) { // We need to make a new page. PT(DynamicTextPage) page = new DynamicTextPage(this); _pages.push_back(page); - return page->slot_glyph(x_size, y_size, _margin); + return page->slot_glyph(x_size, y_size, _texture_margin); } diff --git a/panda/src/text/dynamicTextFont.h b/panda/src/text/dynamicTextFont.h index b8f440cd9c..6544e5631c 100644 --- a/panda/src/text/dynamicTextFont.h +++ b/panda/src/text/dynamicTextFont.h @@ -44,11 +44,18 @@ //////////////////////////////////////////////////////////////////// class EXPCL_PANDA DynamicTextFont : public TextFont { PUBLISHED: - DynamicTextFont(const Filename &font_filename, int face_index, - float point_size, float pixels_per_unit); + DynamicTextFont(const Filename &font_filename, int face_index = 0); - INLINE void set_margin(int margin); - INLINE int get_margin() const; + INLINE bool set_point_size(float point_size); + INLINE float get_point_size() const; + + INLINE bool set_pixels_per_unit(float pixels_per_unit); + INLINE float get_pixels_per_unit() const; + + INLINE void set_texture_margin(int texture_margin); + INLINE int get_texture_margin() const; + INLINE void set_poly_margin(float poly_margin); + INLINE float get_poly_margin() const; INLINE void set_page_size(int x_size, int y_size); INLINE int get_page_x_size() const; @@ -57,20 +64,25 @@ PUBLISHED: int get_num_pages() const; DynamicTextPage *get_page(int n) const; + void clear(); + virtual void write(ostream &out, int indent_level) const; public: virtual const TextGlyph *get_glyph(int character); private: + bool reset_scale(); DynamicTextGlyph *make_glyph(int character); DynamicTextGlyph *slot_glyph(int x_size, int y_size); static void initialize_ft_library(); - int _margin; - int _page_x_size, _page_y_size; + float _point_size; float _pixels_per_unit; + int _texture_margin; + float _poly_margin; + int _page_x_size, _page_y_size; typedef pvector< PT(DynamicTextPage) > Pages; Pages _pages; diff --git a/panda/src/text/dynamicTextGlyph.cxx b/panda/src/text/dynamicTextGlyph.cxx index 5f0d150df4..865cfdeaf9 100644 --- a/panda/src/text/dynamicTextGlyph.cxx +++ b/panda/src/text/dynamicTextGlyph.cxx @@ -63,18 +63,18 @@ get_row(int y) { //////////////////////////////////////////////////////////////////// void DynamicTextGlyph:: make_geom(int bitmap_top, int bitmap_left, - float advance, float pixels_per_unit) { + float advance, float poly_margin, float pixels_per_unit) { // Determine the corners of the rectangle in geometric units. - float top = (bitmap_top + _margin) / pixels_per_unit; - float left = (bitmap_left - _margin) / pixels_per_unit; - float bottom = (bitmap_top - _y_size - _margin) / pixels_per_unit; - float right = (bitmap_left + _x_size + _margin) / pixels_per_unit; + float top = (bitmap_top + poly_margin) / pixels_per_unit; + float left = (bitmap_left - poly_margin) / pixels_per_unit; + float bottom = (bitmap_top - _y_size - poly_margin) / pixels_per_unit; + float right = (bitmap_left + _x_size + poly_margin) / pixels_per_unit; // And the corresponding corners in UV units. - float uv_top = 1.0f - (float)_y / _page->get_y_size(); - float uv_left = (float)_x / _page->get_x_size(); - float uv_bottom = 1.0f - (float)(_y + _y_size) / _page->get_y_size(); - float uv_right = (float)(_x + _x_size) / _page->get_x_size(); + float uv_top = 1.0f - (float)(_y - poly_margin) / _page->get_y_size(); + float uv_left = (float)(_x - poly_margin) / _page->get_x_size(); + float uv_bottom = 1.0f - (float)(_y + _y_size + poly_margin) / _page->get_y_size(); + float uv_right = (float)(_x + _x_size + poly_margin) / _page->get_x_size(); // Create a corresponding tristrip. _geom = new GeomTristrip; diff --git a/panda/src/text/dynamicTextGlyph.h b/panda/src/text/dynamicTextGlyph.h index b22e634fe0..fe0c90b407 100644 --- a/panda/src/text/dynamicTextGlyph.h +++ b/panda/src/text/dynamicTextGlyph.h @@ -41,7 +41,8 @@ public: INLINE bool intersects(int x, int y, int x_size, int y_size) const; unsigned char *get_row(int y); - void make_geom(int top, int left, float advance, float pixels_per_unit); + void make_geom(int top, int left, float advance, float poly_margin, + float pixels_per_unit); DynamicTextPage *_page;