From 1c34c0981e0c2606ec81c404916f61d8cc9e7119 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Tue, 4 Mar 2003 12:34:42 +0000 Subject: [PATCH] Further improvements to osgText and the freetype plugin, handling different font sizes better and plugin removal safely. --- examples/osghud/osghud.cpp | 2 +- examples/osgtext/osgtext.cpp | 8 ++--- include/osg/ref_ptr | 4 ++- include/osgText/Font | 18 ++++++++--- include/osgText/Text | 4 +++ src/Demos/osghud/osghud.cpp | 2 +- src/osgPlugins/freetype/FreeTypeFont.cpp | 17 +++++++--- src/osgPlugins/freetype/FreeTypeFont.h | 2 ++ src/osgPlugins/freetype/FreeTypeLibrary.cpp | 28 ++++++++++++++++- src/osgPlugins/freetype/FreeTypeLibrary.h | 3 ++ src/osgText/DefaultFont.cpp | 35 ++++++++++++++++++--- src/osgText/Font.cpp | 16 +++++++--- src/osgText/Text.cpp | 15 +++++++-- 13 files changed, 125 insertions(+), 29 deletions(-) diff --git a/examples/osghud/osghud.cpp b/examples/osghud/osghud.cpp index febd77827..f5231ca2c 100644 --- a/examples/osghud/osghud.cpp +++ b/examples/osghud/osghud.cpp @@ -79,7 +79,7 @@ osg::Node* createHUD() geode->addDrawable( text ); text->setFont(timesFont); - text->setText("Then place a osg::Projection node above the subgraph\nto create an othrograph projection."); + text->setText("Then place a osg::Projection node above the subgraph\nto create an orthographic projection."); text->setPosition(position); position += delta; diff --git a/examples/osgtext/osgtext.cpp b/examples/osgtext/osgtext.cpp index 2ecff8871..dde72718d 100644 --- a/examples/osgtext/osgtext.cpp +++ b/examples/osgtext/osgtext.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -49,7 +50,7 @@ osg::Group* createHUDText() osgText::Text* text4 = new osgText::Text; text4->setFont(osgText::readFontFile("fonts/times.ttf")); - text4->setFontSize(64,64); + text4->setFontSize(128,128); text4->setPosition(osg::Vec3(200.0f,200.0f,0.0f)); text4->setLayout(osgText::Text::RIGHT_TO_LEFT); text4->setDrawMode(osgText::Text::TEXT|osgText::Text::ALIGNMENT|osgText::Text::BOUNDINGBOX); @@ -126,7 +127,6 @@ osg::Group* create3DText() int main( int argc, char **argv ) { - // use an ArgumentParser object to manage the program arguments. osg::ArgumentParser arguments(&argc,argv); @@ -211,7 +211,7 @@ int main( int argc, char **argv ) // set the scene to render viewer.setSceneData(rootNode.get()); - + // create the windows and run the threads. viewer.realize(Producer::CameraGroup::ThreadPerCamera); @@ -228,6 +228,6 @@ int main( int argc, char **argv ) viewer.frame(); } - + return 0; } diff --git a/include/osg/ref_ptr b/include/osg/ref_ptr index b48e03f31..aec0d39f9 100644 --- a/include/osg/ref_ptr +++ b/include/osg/ref_ptr @@ -108,7 +108,9 @@ class ref_ptr * return the pointer to the object. * Note, do not use this unless you are 100% sure your code handles the deletion of the object correctly, and * only use when absolutely required.*/ - inline T* take() { T* tmp=_ptr; if (_ptr) _ptr->unref_nodelete(); _ptr=0; return tmp;} + inline T* take() { return release();} + + inline T* release() { T* tmp=_ptr; if (_ptr) _ptr->unref_nodelete(); _ptr=0; return tmp;} private: T* _ptr; diff --git a/include/osgText/Font b/include/osgText/Font index f9ddf3b09..dd7acd436 100644 --- a/include/osgText/Font +++ b/include/osgText/Font @@ -23,10 +23,12 @@ #include #include +#include namespace osgText { class Font; +class Text; /** read a font from specified file.*/ extern OSGTEXT_EXPORT Font* readFontFile(const std::string& filename); @@ -66,21 +68,30 @@ public: virtual bool hasVertical() const = 0; + // make Text a friend to allow it add and remove its entry in the Font's _textList. + friend Text; protected: virtual ~Font(); - void addGlyph(unsigned int charcode, Glyph* glyph); + void addGlyph(unsigned int width, unsigned int height, unsigned int charcode, Glyph* glyph); typedef std::vector< osg::ref_ptr > GlyphTextureList; typedef std::vector< osg::ref_ptr > StateSetList; typedef std::map< unsigned int, osg::ref_ptr > GlyphMap; - GlyphMap _glyphMap; + typedef std::pair< unsigned int, unsigned int > SizePair; + typedef std::map< SizePair, GlyphMap > SizeGlyphMap; + typedef std::set< Text* > TextList; + + SizeGlyphMap _sizeGlyphMap; GlyphTextureList _glyphTextureList; StateSetList _stateSetList; + // list of text object to contact when Font is forcebly removed. + TextList _textList; + // current active size of font unsigned int _width; unsigned int _height; @@ -135,9 +146,6 @@ public: unsigned int getGlyphCode() const; - void setFont(Font* font); - Font* getFont() const; - void setHorizontalBearing(const osg::Vec2& bearing); const osg::Vec2& getHorizontalBearing() const; diff --git a/include/osgText/Text b/include/osgText/Text index 55cef7fb4..637783d36 100644 --- a/include/osgText/Text +++ b/include/osgText/Text @@ -182,6 +182,10 @@ public: /** Draw the text.*/ virtual void drawImplementation(osg::State& state) const; + // make Font a friend to allow it set the _font to 0 if the font is + // forcefully unloaded. + friend Font; + protected: virtual ~Text(); diff --git a/src/Demos/osghud/osghud.cpp b/src/Demos/osghud/osghud.cpp index e35040eac..2344f7f91 100644 --- a/src/Demos/osghud/osghud.cpp +++ b/src/Demos/osghud/osghud.cpp @@ -109,7 +109,7 @@ osg::Node* createHUD() geode->addDrawable( text ); text->setFont(timesFont); - text->setText("Then place a osg::Projection node above the subgraph\nto create an othrograph projection."); + text->setText("Then place a osg::Projection node above the subgraph\nto create an orthographic projection."); text->setPosition(position); position += delta; diff --git a/src/osgPlugins/freetype/FreeTypeFont.cpp b/src/osgPlugins/freetype/FreeTypeFont.cpp index ab7fda509..1e2a61af9 100644 --- a/src/osgPlugins/freetype/FreeTypeFont.cpp +++ b/src/osgPlugins/freetype/FreeTypeFont.cpp @@ -22,6 +22,10 @@ FreeTypeFont::FreeTypeFont(const std::string& filename, FT_Face face): { } +FreeTypeFont::~FreeTypeFont() +{ +} + void FreeTypeFont::setSize(unsigned int width, unsigned int height) { FT_Error error = FT_Set_Pixel_Sizes( _face, /* handle to face object */ @@ -42,9 +46,13 @@ void FreeTypeFont::setSize(unsigned int width, unsigned int height) osgText::Font::Glyph* FreeTypeFont::getGlyph(unsigned int charcode) { - // search for glyph amoungst existing glyphs. - GlyphMap::iterator itr = _glyphMap.find(charcode); - if (itr!=_glyphMap.end()) return itr->second.get(); + SizeGlyphMap::iterator itr = _sizeGlyphMap.find(SizePair(_width,_height)); + if (itr!=_sizeGlyphMap.end()) + { + GlyphMap& glyphmap = itr->second; + GlyphMap::iterator gitr = glyphmap.find(charcode); + if (gitr!=glyphmap.end()) return gitr->second.get(); + } FT_Error error = FT_Load_Char( _face, charcode, FT_LOAD_RENDER|FT_LOAD_NO_BITMAP ); if (error) @@ -83,13 +91,12 @@ osgText::Font::Glyph* FreeTypeFont::getGlyph(unsigned int charcode) FT_Glyph_Metrics* metrics = &(glyphslot->metrics); - glyph->setFont(this); glyph->setHorizontalBearing(osg::Vec2((float)metrics->horiBearingX/64.0f,(float)(metrics->horiBearingY-metrics->height)/64.0f)); // bottom left. glyph->setHorizontalAdvance((float)metrics->horiAdvance/64.0f); glyph->setVerticalBearing(osg::Vec2((float)metrics->vertBearingX/64.0f,(float)(metrics->vertBearingY-metrics->height)/64.0f)); // top middle. glyph->setVerticalAdvance((float)metrics->vertAdvance/64.0f); - addGlyph(charcode,glyph.get()); + addGlyph(_width,_height,charcode,glyph.get()); return glyph.get(); diff --git a/src/osgPlugins/freetype/FreeTypeFont.h b/src/osgPlugins/freetype/FreeTypeFont.h index f9d9d5605..56d2c7596 100644 --- a/src/osgPlugins/freetype/FreeTypeFont.h +++ b/src/osgPlugins/freetype/FreeTypeFont.h @@ -26,6 +26,8 @@ public: FreeTypeFont(const std::string& filename, FT_Face face); + virtual ~FreeTypeFont(); + virtual std::string getFileName() const { return _filename; } virtual void setSize(unsigned int width, unsigned int height); diff --git a/src/osgPlugins/freetype/FreeTypeLibrary.cpp b/src/osgPlugins/freetype/FreeTypeLibrary.cpp index feb99b461..ffd58077b 100644 --- a/src/osgPlugins/freetype/FreeTypeLibrary.cpp +++ b/src/osgPlugins/freetype/FreeTypeLibrary.cpp @@ -26,6 +26,26 @@ FreeTypeLibrary::FreeTypeLibrary() FreeTypeLibrary::~FreeTypeLibrary() { + + for(FontMap::iterator itr=_fontMap.begin(); + itr!=_fontMap.end(); + ++itr) + { + FreeTypeFont* freetypefont = itr->second.get(); + if (freetypefont->referenceCount()>1) + { + // external references must exist... + itr->second = 0; + + delete freetypefont; + } + else + { + // no external references exist so its safe to delete via set the ref_ptr to 0. + itr->second = 0; + } + } + FT_Done_FreeType( _ftlibrary); } @@ -37,6 +57,10 @@ FreeTypeLibrary* FreeTypeLibrary::instance() FreeTypeFont* FreeTypeLibrary::getFont(const std::string& fontfile,unsigned int index) { + + FontMap::iterator itr = _fontMap.find(fontfile); + if (itr!=_fontMap.end()) return itr->second.get(); + FT_Face face; /* handle to face object */ FT_Error error = FT_New_Face( _ftlibrary, fontfile.c_str(), index, &face ); if (error == FT_Err_Unknown_File_Format) @@ -52,6 +76,8 @@ FreeTypeFont* FreeTypeLibrary::getFont(const std::string& fontfile,unsigned int return 0; } - return new FreeTypeFont(fontfile,face); + FreeTypeFont* font = new FreeTypeFont(fontfile,face); + _fontMap[fontfile]=font; + return font; } diff --git a/src/osgPlugins/freetype/FreeTypeLibrary.h b/src/osgPlugins/freetype/FreeTypeLibrary.h index 4e6f2f29d..bd4fd8992 100644 --- a/src/osgPlugins/freetype/FreeTypeLibrary.h +++ b/src/osgPlugins/freetype/FreeTypeLibrary.h @@ -34,8 +34,11 @@ protected: * library is via the singleton instance method.*/ FreeTypeLibrary(); + typedef std::map< std::string, osg::ref_ptr > FontMap; + FT_Library _ftlibrary; + FontMap _fontMap; }; diff --git a/src/osgText/DefaultFont.cpp b/src/osgText/DefaultFont.cpp index 51a0d3d7e..dd3568b7a 100644 --- a/src/osgText/DefaultFont.cpp +++ b/src/osgText/DefaultFont.cpp @@ -44,8 +44,36 @@ void DefaultFont::setSize(unsigned int, unsigned int) Font::Glyph* DefaultFont::getGlyph(unsigned int charcode) { - GlyphMap::iterator itr = _glyphMap.find(charcode); - if (itr!=_glyphMap.end()) return itr->second.get(); + if (_sizeGlyphMap.empty()) return 0; + + SizeGlyphMap::iterator itr = _sizeGlyphMap.find(SizePair(_width,_height)); + if (itr==_sizeGlyphMap.end()) + { + // no font found of correct size, will need to find the nearest. + itr = _sizeGlyphMap.begin(); + int mindeviation = abs(_width-itr->first.first)+ + abs(_height-itr->first.second); + SizeGlyphMap::iterator sitr=itr; + ++sitr; + for(; + sitr!=_sizeGlyphMap.end(); + ++sitr) + { + int deviation = abs(_width-sitr->first.first)+ + abs(_height-sitr->first.second); + if (deviationsecond; + GlyphMap::iterator gitr = glyphmap.find(charcode); + + if (gitr!=glyphmap.end()) return gitr->second.get(); else return 0; } @@ -203,13 +231,12 @@ void DefaultFont::constructGlyphs() } - glyph->setFont(this); glyph->setHorizontalBearing(osg::Vec2(0.0f,0.0f)); // bottom left. glyph->setHorizontalAdvance((float)_width); glyph->setVerticalBearing(osg::Vec2((float)_width*0.5f,(float)_height)); // top middle. glyph->setVerticalAdvance((float)_height); - addGlyph(i,glyph.get()); + addGlyph(_width,_height,i,glyph.get()); } } diff --git a/src/osgText/Font.cpp b/src/osgText/Font.cpp index 2b43ff06a..5745f7666 100644 --- a/src/osgText/Font.cpp +++ b/src/osgText/Font.cpp @@ -12,6 +12,7 @@ */ #include +#include #include #include @@ -82,11 +83,18 @@ Font::Font(): Font::~Font() { + for(TextList::iterator itr=_textList.begin(); + itr!=_textList.end(); + ++itr) + { + Text* text = *itr; + text->_font.release(); + } } -void Font::addGlyph(unsigned int charcode, Glyph* glyph) +void Font::addGlyph(unsigned int width, unsigned int height, unsigned int charcode, Glyph* glyph) { - _glyphMap[charcode]=glyph; + _sizeGlyphMap[SizePair(width,height)][charcode]=glyph; int posX=0,posY=0; @@ -297,8 +305,8 @@ Font::Glyph::~Glyph() {} unsigned int Font::Glyph::getGlyphCode() const { return _glyphCode; } -void Font::Glyph::setFont(Font* font) { _font = font; } -Font* Font::Glyph::getFont() const { return _font; } +// void Font::Glyph::setFont(Font* font) { _font = font; } +// Font* Font::Glyph::getFont() const { return _font; } void Font::Glyph::setHorizontalBearing(const osg::Vec2& bearing) { _horizontalBearing=bearing; } const osg::Vec2& Font::Glyph::getHorizontalBearing() const { return _horizontalBearing; } diff --git a/src/osgText/Text.cpp b/src/osgText/Text.cpp index 4371a6942..ccd0d4217 100644 --- a/src/osgText/Text.cpp +++ b/src/osgText/Text.cpp @@ -51,15 +51,26 @@ Text::Text(const Text& text,const osg::CopyOp& copyop): _color(text._color), _drawMode(text._drawMode) { + if (_font.valid()) _font->_textList.insert(this); } Text::~Text() { + if (_font.valid()) _font->_textList.erase(this); } void Text::setFont(Font* font) { + if (_font==font) return; + + // unregister from the old font. + if (_font.valid()) _font->_textList.erase(this); + _font = font; + + // register with the new font. + if (_font.valid()) _font->_textList.insert(this); + computeGlyphRepresentation(); } @@ -393,8 +404,6 @@ void Text::computePositions() void Text::drawImplementation(osg::State& state) const { - - glPushMatrix(); // draw part. @@ -424,7 +433,7 @@ void Text::drawImplementation(osg::State& state) const if (_drawMode & TEXT) { - bool first = true; + bool first = false; for(TextureGlyphQuadMap::const_iterator titr=_textureGlyphQuadMap.begin(); titr!=_textureGlyphQuadMap.end();