Further improvements to osgText and the freetype plugin, handling different
font sizes better and plugin removal safely.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <osgUtil/Optimizer>
|
||||
#include <osgDB/ReadFile>
|
||||
#include <osgDB/Registry>
|
||||
#include <osgProducer/Viewer>
|
||||
|
||||
#include <osg/Material>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -23,10 +23,12 @@
|
||||
#include <osgText/Export>
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
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<GlyphTexture> > GlyphTextureList;
|
||||
typedef std::vector< osg::ref_ptr<osg::StateSet> > StateSetList;
|
||||
typedef std::map< unsigned int, osg::ref_ptr<Glyph> > 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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -34,8 +34,11 @@ protected:
|
||||
* library is via the singleton instance method.*/
|
||||
FreeTypeLibrary();
|
||||
|
||||
typedef std::map< std::string, osg::ref_ptr<FreeTypeFont> > FontMap;
|
||||
|
||||
|
||||
FT_Library _ftlibrary;
|
||||
FontMap _fontMap;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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 (deviation<mindeviation)
|
||||
{
|
||||
mindeviation = deviation;
|
||||
itr = sitr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// new find the glyph for the required charcode.
|
||||
GlyphMap& glyphmap = itr->second;
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
#include <osgText/Font>
|
||||
#include <osgText/Text>
|
||||
|
||||
#include <osg/State>
|
||||
#include <osg/Notify>
|
||||
@@ -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; }
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user