From e869200b3dc3ebe788e5b4b16004dc477b133ce7 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 25 Feb 2008 12:54:54 +0000 Subject: [PATCH] Refactored the mutex usage in osgText and freetype plugin to prevent multi-thread crash --- examples/osgtext/osgtext.cpp | 740 ++++---------------- include/osgText/Font | 7 +- include/osgText/Font3D | 3 - src/osgPlugins/freetype/FreeTypeFont.cpp | 5 +- src/osgPlugins/freetype/FreeTypeFont.h | 1 - src/osgPlugins/freetype/FreeTypeLibrary.cpp | 12 +- src/osgPlugins/freetype/FreeTypeLibrary.h | 9 +- src/osgText/Font.cpp | 23 +- src/osgText/Font3D.cpp | 6 - src/osgText/Text3D.cpp | 2 - 10 files changed, 169 insertions(+), 639 deletions(-) diff --git a/examples/osgtext/osgtext.cpp b/examples/osgtext/osgtext.cpp index 32ff5adec..fb7ddca29 100644 --- a/examples/osgtext/osgtext.cpp +++ b/examples/osgtext/osgtext.cpp @@ -36,683 +36,213 @@ #include -osg::Group* createHUDText() -{ - - osg::Group* rootNode = new osg::Group; - - osgText::Font* font = osgText::readFontFile("fonts/arial.ttf"); - - osg::Geode* geode = new osg::Geode; - rootNode->addChild(geode); - - float windowHeight = 1024.0f; - float windowWidth = 1280.0f; - float margin = 50.0f; - - -//////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Examples of how to set up different text layout -// - - osg::Vec4 layoutColor(1.0f,1.0f,0.0f,1.0f); - float layoutCharacterSize = 20.0f; - - { - osgText::Text* text = new osgText::Text; - text->setFont(font); - text->setColor(layoutColor); - text->setCharacterSize(layoutCharacterSize); - text->setPosition(osg::Vec3(margin,windowHeight-margin,0.0f)); - - // the default layout is left to right, typically used in languages - // originating from europe such as English, French, German, Spanish etc.. - text->setLayout(osgText::Text::LEFT_TO_RIGHT); - - text->setText("text->setLayout(osgText::Text::LEFT_TO_RIGHT);"); - geode->addDrawable(text); - } - - { - osgText::Text* text = new osgText::Text; - text->setFont(font); - text->setColor(layoutColor); - text->setCharacterSize(layoutCharacterSize); - text->setPosition(osg::Vec3(windowWidth-margin,windowHeight-margin,0.0f)); - - // right to left layouts would be used for hebrew or arabic fonts. - text->setLayout(osgText::Text::RIGHT_TO_LEFT); - text->setAlignment(osgText::Text::RIGHT_BASE_LINE); - - text->setText("text->setLayout(osgText::Text::RIGHT_TO_LEFT);"); - geode->addDrawable(text); - } - - { - osgText::Text* text = new osgText::Text; - text->setFont(font); - text->setColor(layoutColor); - text->setPosition(osg::Vec3(margin,windowHeight-margin,0.0f)); - text->setCharacterSize(layoutCharacterSize); - - // vertical font layout would be used for asian fonts. - text->setLayout(osgText::Text::VERTICAL); - - text->setText("text->setLayout(osgText::Text::VERTICAL);"); - geode->addDrawable(text); - } - - -//////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Examples of how to set up different font resolution -// - - osg::Vec4 fontSizeColor(0.0f,1.0f,1.0f,1.0f); - float fontSizeCharacterSize = 30; - - osg::Vec3 cursor = osg::Vec3(margin*2,windowHeight-margin*2,0.0f); - - { - osgText::Text* text = new osgText::Text; - text->setFont(font); - text->setColor(fontSizeColor); - text->setCharacterSize(fontSizeCharacterSize); - text->setPosition(cursor); - - // use text that uses 10 by 10 texels as a target resolution for fonts. - text->setFontResolution(10,10); // blocky but small texture memory usage - - text->setText("text->setFontResolution(10,10); // blocky but small texture memory usage"); - geode->addDrawable(text); - } - - cursor.y() -= fontSizeCharacterSize; - { - osgText::Text* text = new osgText::Text; - text->setFont(font); - text->setColor(fontSizeColor); - text->setCharacterSize(fontSizeCharacterSize); - text->setPosition(cursor); - - // use text that uses 20 by 20 texels as a target resolution for fonts. - text->setFontResolution(20,20); // smoother but higher texture memory usage (but still quite low). - - text->setText("text->setFontResolution(20,20); // smoother but higher texture memory usage (but still quite low)."); - geode->addDrawable(text); - } - - cursor.y() -= fontSizeCharacterSize; - { - osgText::Text* text = new osgText::Text; - text->setFont(font); - text->setColor(fontSizeColor); - text->setCharacterSize(fontSizeCharacterSize); - text->setPosition(cursor); - - // use text that uses 40 by 40 texels as a target resolution for fonts. - text->setFontResolution(40,40); // even smoother but again higher texture memory usage. - - text->setText("text->setFontResolution(40,40); // even smoother but again higher texture memory usage."); - geode->addDrawable(text); - } - - -//////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Examples of how to set up different sized text -// - - osg::Vec4 characterSizeColor(1.0f,0.0f,1.0f,1.0f); - - cursor.y() -= fontSizeCharacterSize*2.0f; - - { - osgText::Text* text = new osgText::Text; - text->setFont(font); - text->setColor(characterSizeColor); - text->setFontResolution(20,20); - text->setPosition(cursor); - - // use text that is 20 units high. - text->setCharacterSize(20); // small - - text->setText("text->setCharacterSize(20.0f); // small"); - geode->addDrawable(text); - } - - cursor.y() -= 30.0f; - { - osgText::Text* text = new osgText::Text; - text->setFont(font); - text->setColor(characterSizeColor); - text->setFontResolution(30,30); - text->setPosition(cursor); - - // use text that is 30 units high. - text->setCharacterSize(30.0f); // medium - - text->setText("text->setCharacterSize(30.0f); // medium"); - geode->addDrawable(text); - } - - cursor.y() -= 50.0f; - { - osgText::Text* text = new osgText::Text; - text->setFont(font); - text->setColor(characterSizeColor); - text->setFontResolution(40,40); - text->setPosition(cursor); - - // use text that is 60 units high. - text->setCharacterSize(60.0f); // large - - text->setText("text->setCharacterSize(60.0f); // large"); - geode->addDrawable(text); - } - - -//////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Examples of how to set up different alignments -// - - osg::Vec4 alignmentSizeColor(0.0f,1.0f,0.0f,1.0f); - float alignmentCharacterSize = 25.0f; - cursor.x() = 640; - cursor.y() = margin*4.0f; - - typedef std::pair AlignmentPair; - typedef std::vector AlignmentList; - AlignmentList alignmentList; - alignmentList.push_back(AlignmentPair(osgText::Text::LEFT_TOP,"text->setAlignment(\nosgText::Text::LEFT_TOP);")); - alignmentList.push_back(AlignmentPair(osgText::Text::LEFT_CENTER,"text->setAlignment(\nosgText::Text::LEFT_CENTER);")); - alignmentList.push_back(AlignmentPair(osgText::Text::LEFT_BOTTOM,"text->setAlignment(\nosgText::Text::LEFT_BOTTOM);")); - alignmentList.push_back(AlignmentPair(osgText::Text::CENTER_TOP,"text->setAlignment(\nosgText::Text::CENTER_TOP);")); - alignmentList.push_back(AlignmentPair(osgText::Text::CENTER_CENTER,"text->setAlignment(\nosgText::Text::CENTER_CENTER);")); - alignmentList.push_back(AlignmentPair(osgText::Text::CENTER_BOTTOM,"text->setAlignment(\nosgText::Text::CENTER_BOTTOM);")); - alignmentList.push_back(AlignmentPair(osgText::Text::RIGHT_TOP,"text->setAlignment(\nosgText::Text::RIGHT_TOP);")); - alignmentList.push_back(AlignmentPair(osgText::Text::RIGHT_CENTER,"text->setAlignment(\nosgText::Text::RIGHT_CENTER);")); - alignmentList.push_back(AlignmentPair(osgText::Text::RIGHT_BOTTOM,"text->setAlignment(\nosgText::Text::RIGHT_BOTTOM);")); - alignmentList.push_back(AlignmentPair(osgText::Text::LEFT_BASE_LINE,"text->setAlignment(\nosgText::Text::LEFT_BASE_LINE);")); - alignmentList.push_back(AlignmentPair(osgText::Text::CENTER_BASE_LINE,"text->setAlignment(\nosgText::Text::CENTER_BASE_LINE);")); - alignmentList.push_back(AlignmentPair(osgText::Text::RIGHT_BASE_LINE,"text->setAlignment(\nosgText::Text::RIGHT_BASE_LINE);")); - alignmentList.push_back(AlignmentPair(osgText::Text::LEFT_BOTTOM_BASE_LINE,"text->setAlignment(\nosgText::Text::LEFT_BOTTOM_BASE_LINE);")); - alignmentList.push_back(AlignmentPair(osgText::Text::CENTER_BOTTOM_BASE_LINE,"text->setAlignment(\nosgText::Text::CENTER_BOTTOM_BASE_LINE);")); - alignmentList.push_back(AlignmentPair(osgText::Text::RIGHT_BOTTOM_BASE_LINE,"text->setAlignment(\nosgText::Text::RIGHT_BOTTOM_BASE_LINE);")); - - - osg::Sequence* sequence = new osg::Sequence; - { - for(AlignmentList::iterator itr=alignmentList.begin(); - itr!=alignmentList.end(); - ++itr) - { - osg::Geode* alignmentGeode = new osg::Geode; - sequence->addChild(alignmentGeode); - sequence->setTime(sequence->getNumChildren(), 1.0f); - - osgText::Text* text = new osgText::Text; - text->setFont(font); - text->setColor(alignmentSizeColor); - text->setCharacterSize(alignmentCharacterSize); - text->setPosition(cursor); - text->setDrawMode(osgText::Text::TEXT|osgText::Text::ALIGNMENT|osgText::Text::BOUNDINGBOX); - - text->setAlignment(itr->first); - text->setText(itr->second); - - alignmentGeode->addDrawable(text); - - - } - - } - - sequence->setMode(osg::Sequence::START); - sequence->setInterval(osg::Sequence::LOOP, 0, -1); - sequence->setDuration(1.0f, -1); - - rootNode->addChild(sequence); - - -//////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Examples of how to set up different fonts... -// - - cursor.x() = margin*2.0f; - cursor.y() = margin*2.0f; - - osg::Vec4 fontColor(1.0f,0.5f,0.0f,1.0f); - float fontCharacterSize = 20.0f; - float spacing = 40.0f; - - { - osgText::Text* text = new osgText::Text; - text->setColor(fontColor); - text->setPosition(cursor); - text->setCharacterSize(fontCharacterSize); - - text->setFont(0); - text->setText("text->setFont(0); // inbuilt font."); - geode->addDrawable(text); - - cursor.x() = text->getBound().xMax() + spacing ; - } - - { - osgText::Font* arial = osgText::readFontFile("fonts/arial.ttf"); - - osgText::Text* text = new osgText::Text; - text->setColor(fontColor); - text->setPosition(cursor); - text->setCharacterSize(fontCharacterSize); - - text->setFont(arial); - text->setText(arial!=0? - "text->setFont(\"fonts/arial.ttf\");": - "unable to load \"fonts/arial.ttf\""); - geode->addDrawable(text); - - cursor.x() = text->getBound().xMax() + spacing ; - } - - { - osgText::Font* times = osgText::readFontFile("fonts/times.ttf"); - - osgText::Text* text = new osgText::Text; - text->setColor(fontColor); - text->setPosition(cursor); - text->setCharacterSize(fontCharacterSize); - - geode->addDrawable(text); - text->setFont(times); - text->setText(times!=0? - "text->setFont(\"fonts/times.ttf\");": - "unable to load \"fonts/times.ttf\""); - - cursor.x() = text->getBound().xMax() + spacing ; - } - - cursor.x() = margin*2.0f; - cursor.y() = margin; - - { - osgText::Font* dirtydoz = osgText::readFontFile("fonts/dirtydoz.ttf"); - - osgText::Text* text = new osgText::Text; - text->setColor(fontColor); - text->setPosition(cursor); - text->setCharacterSize(fontCharacterSize); - - text->setFont(dirtydoz); - text->setText(dirtydoz!=0? - "text->setFont(\"fonts/dirtydoz.ttf\");": - "unable to load \"fonts/dirtydoz.ttf\""); - geode->addDrawable(text); - - cursor.x() = text->getBound().xMax() + spacing ; - } - - { - osgText::Font* fudd = osgText::readFontFile("fonts/fudd.ttf"); - - osgText::Text* text = new osgText::Text; - text->setColor(fontColor); - text->setPosition(cursor); - text->setCharacterSize(fontCharacterSize); - - text->setFont(fudd); - text->setText(fudd!=0? - "text->setFont(\"fonts/fudd.ttf\");": - "unable to load \"fonts/fudd.ttf\""); - geode->addDrawable(text); - - cursor.x() = text->getBound().xMax() + spacing ; - } - - return rootNode; -} -// create text which sits in 3D space such as would be inserted into a normal model -osg::Group* create3DText(const osg::Vec3& center,float radius) -{ - - osg::Geode* geode = new osg::Geode; - -//////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Examples of how to set up axis/orientation alignments -// - - float characterSize=radius*0.2f; - - osg::Vec3 pos(center.x()-radius*.5f,center.y()-radius*.5f,center.z()-radius*.5f); - - osgText::Text* text1 = new osgText::Text; - text1->setFont("fonts/times.ttf"); - text1->setCharacterSize(characterSize); - text1->setPosition(pos); - text1->setAxisAlignment(osgText::Text::XY_PLANE); - text1->setText("XY_PLANE"); - geode->addDrawable(text1); - - osgText::Text* text2 = new osgText::Text; - text2->setFont("fonts/times.ttf"); - text2->setCharacterSize(characterSize); - text2->setPosition(pos); - text2->setAxisAlignment(osgText::Text::YZ_PLANE); - text2->setText("YZ_PLANE"); - geode->addDrawable(text2); - - osgText::Text* text3 = new osgText::Text; - text3->setFont("fonts/times.ttf"); - text3->setCharacterSize(characterSize); - text3->setPosition(pos); - text3->setAxisAlignment(osgText::Text::XZ_PLANE); - text3->setText("XZ_PLANE"); - geode->addDrawable(text3); - - - osgText::Text* text4 = new osgText::Text; - text4->setFont("fonts/times.ttf"); - text4->setCharacterSize(characterSize); - text4->setPosition(center); - text4->setAxisAlignment(osgText::Text::SCREEN); - - osg::Vec4 characterSizeModeColor(1.0f,0.0f,0.5f,1.0f); - - osgText::Text* text5 = new osgText::Text; - text5->setColor(characterSizeModeColor); - text5->setFont("fonts/times.ttf"); - //text5->setCharacterSize(characterSize); - text5->setCharacterSize(32.0f); // medium - text5->setPosition(center - osg::Vec3(0.0, 0.0, 0.2)); - text5->setAxisAlignment(osgText::Text::SCREEN); - text5->setCharacterSizeMode(osgText::Text::SCREEN_COORDS); - text5->setText("CharacterSizeMode SCREEN_COORDS(size 32.0)"); - geode->addDrawable(text5); - - osgText::Text* text6 = new osgText::Text; - text6->setColor(characterSizeModeColor); - text6->setFont("fonts/times.ttf"); - text6->setCharacterSize(characterSize); - text6->setPosition(center - osg::Vec3(0.0, 0.0, 0.4)); - text6->setAxisAlignment(osgText::Text::SCREEN); - text6->setCharacterSizeMode(osgText::Text::OBJECT_COORDS_WITH_MAXIMUM_SCREEN_SIZE_CAPPED_BY_FONT_HEIGHT); - text6->setText("CharacterSizeMode OBJECT_COORDS_WITH_MAXIMUM_SCREEN_SIZE_CAPPED_BY_FONT_HEIGHT"); - geode->addDrawable(text6); - - osgText::Text* text7 = new osgText::Text; - text7->setColor(characterSizeModeColor); - text7->setFont("fonts/times.ttf"); - text7->setCharacterSize(characterSize); - text7->setPosition(center - osg::Vec3(0.0, 0.0, 0.6)); - text7->setAxisAlignment(osgText::Text::SCREEN); - text7->setCharacterSizeMode(osgText::Text::OBJECT_COORDS); - text7->setText("CharacterSizeMode OBJECT_COORDS (default)"); - geode->addDrawable(text7); - -#if 1 - // reproduce outline bounding box compute problem with backdrop on. - text4->setBackdropType(osgText::Text::OUTLINE); - text4->setDrawMode(osgText::Text::TEXT | osgText::Text::BOUNDINGBOX); -#endif - - text4->setText("SCREEN"); - geode->addDrawable(text4); - - osg::ShapeDrawable* shape = new osg::ShapeDrawable(new osg::Sphere(center,characterSize*0.2f)); - shape->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::ON); - geode->addDrawable(shape); - - osg::Group* rootNode = new osg::Group; - rootNode->addChild(geode); - - return rootNode; -} class UpdateTextOperation : public osg::Operation { public: - UpdateTextOperation(const osg::Vec3& center, float diameter, osg::Group* group): - Operation("UpdateTextOperation", true), - _center(center), - _diameter(diameter), + UpdateTextOperation(osg::Group* group): + Operation("UpdateTextOperation", true), + _group(group), _maxNumChildren(200), - _maxNumTextPerGeode(10), - _group(group) - { - } + _maxNumTextPerGeode(10) + { + } - virtual void operator () (osg::Object* callingObject) - { + virtual void operator () (osg::Object* callingObject) + { // decided which method to call according to whole has called me. osgViewer::Viewer* viewer = dynamic_cast(callingObject); if (viewer) update(); else load(); - } - - void update() - { + } + + void update() + { // osg::notify(osg::NOTICE)<<"*** Doing update"< lock(_mutex); - + if (_mergeSubgraph.valid()) { - _group->addChild(_mergeSubgraph.get()); + _group->addChild(_mergeSubgraph.get()); - _mergeSubgraph = 0; + _mergeSubgraph = 0; - if (_group->getNumChildren()>_maxNumChildren) + if (_group->getNumChildren()>_maxNumChildren) + { + osg::Geode* geode = dynamic_cast(_group->getChild(0)); + if (geode) { - osg::Geode* geode = dynamic_cast(_group->getChild(0)); - if (geode) - { - _availableSubgraph.push_back(geode); - geode->removeDrawables(0,geode->getNumDrawables()); - } - _group->removeChild(0,1); + _availableSubgraph.push_back(geode); + geode->removeDrawables(0,geode->getNumDrawables()); } - - _waitOnMergeBlock.release(); + _group->removeChild(0,1); + } + + _waitOnMergeBlock.release(); } - } - - void load() - { - + } + + void load() + { + // osg::notify(osg::NOTICE)<<"Doing load"< geode; { - OpenThreads::ScopedLock lock(_mutex); - if (!_availableSubgraph.empty()) - { - geode = _availableSubgraph.front(); - _availableSubgraph.pop_front(); - } + OpenThreads::ScopedLock lock(_mutex); + if (!_availableSubgraph.empty()) + { + geode = _availableSubgraph.front(); + _availableSubgraph.pop_front(); + } } - + if (!geode) geode = new osg::Geode; for(unsigned int i=0; i<_maxNumTextPerGeode; ++i) { - float x = float(rand()) / float(RAND_MAX) - 0.5f; - float y = float(rand()) / float(RAND_MAX) - 0.5f; - float z = float(i) / float(_maxNumTextPerGeode) - 0.5f; - osg::Vec3 position(x, y, z); + osg::Vec3 position(float(rand()) / float(RAND_MAX), float(rand()) / float(RAND_MAX), float(i)/float(_maxNumTextPerGeode)); - std::string str; - unsigned int _numCharacters = 5; - for(unsigned int ni=0; ni<_numCharacters;++ni) - { - str.push_back(char(32.0 + (float(rand())/float(RAND_MAX))*128.0f)); - } - - osgText::Text* text = new osgText::Text; - text->setDataVariance(osg::Object::DYNAMIC); - text->setPosition(_center + position * _diameter); - text->setFont("times.ttf"); - text->setText(str); - text->setCharacterSize(0.025f * _diameter); - text->setAxisAlignment(osgText::Text::SCREEN); - - geode->addDrawable(text); + std::string str; + unsigned int _numCharacters = 5; + for(unsigned int ni=0; ni<_numCharacters;++ni) + { + str.push_back(char(32.0 + (float(rand())/float(RAND_MAX))*128.0f)); + } + + osgText::Text* text = new osgText::Text; + text->setDataVariance(osg::Object::DYNAMIC); + text->setPosition(position); + text->setFont("times.ttf"); + text->setText(str); + text->setCharacterSize(0.025f); + text->setAxisAlignment(osgText::Text::SCREEN); + + geode->addDrawable(text); } { - OpenThreads::ScopedLock lock(_mutex); - _mergeSubgraph = geode; + OpenThreads::ScopedLock lock(_mutex); + _mergeSubgraph = geode; } - + // osg::notify(osg::NOTICE)<<"Waiting on merge"< > AvailableList; + typedef std::list< osg::ref_ptr > AvailableList; - osg::Vec3 _center; - float _diameter; - unsigned int _maxNumChildren; - unsigned int _maxNumTextPerGeode; - - OpenThreads::Mutex _mutex; - osg::ref_ptr _group; - osg::ref_ptr _mergeSubgraph; - AvailableList _availableSubgraph; - OpenThreads::Block _waitOnMergeBlock; - - unsigned int _counter; + unsigned int _maxNumChildren; + unsigned int _maxNumTextPerGeode; + + OpenThreads::Mutex _mutex; + osg::ref_ptr _group; + osg::ref_ptr _mergeSubgraph; + AvailableList _availableSubgraph; + OpenThreads::Block _waitOnMergeBlock; + + unsigned int _counter; }; int main(int argc, char** argv) { - osg::ArgumentParser arguments(&argc, argv); + osg::ArgumentParser arguments(&argc, argv); - // construct the viewer. - osgViewer::Viewer viewer(arguments); - - typedef std::list< osg::ref_ptr > Threads; - Threads operationThreads; - osg::ref_ptr updateOperation; + osg::Referenced::setThreadSafeReferenceCounting(true); - unsigned int numThreads = 0; - if (arguments.read("--mt", numThreads) || arguments.read("--mt")) + // construct the viewer. + osgViewer::Viewer viewer(arguments); + + typedef std::list< osg::ref_ptr > Threads; + + Threads operationThreads; + osg::ref_ptr updateOperation; + + unsigned int numThreads = 0; + if (arguments.read("--mt", numThreads) || arguments.read("--mt")) + { + // construct a multi-threaded text updating test. + if (numThreads==0) numThreads = 1; + + // create a group to add everything into. + osg::Group* mainGroup = new osg::Group; + + osg::ref_ptr loadedModel = osgDB::readNodeFiles(arguments); + mainGroup->addChild(loadedModel.get()); + + for(unsigned int i=0; i loadedModel = osgDB::readNodeFiles(arguments); - if (loadedModel.valid()) - { - mainGroup->addChild(loadedModel.get()); - - center = loadedModel->getBound().center(); - diameter = loadedModel->getBound().radius() * 2.0f; - } - - for(unsigned int i=0; iaddChild(textGroup); + osg::Group* textGroup = new osg::Group; + mainGroup->addChild(textGroup); - // create the background thread - osg::OperationThread* operationThread = new osg::OperationThread; - - operationThreads.push_back(operationThread); + // create the background thread + osg::OperationThread* operationThread = new osg::OperationThread; - // create the operation that will run in the background and - // sync once per frame with the main viewer loop. - updateOperation = new UpdateTextOperation(center, diameter, textGroup); + operationThreads.push_back(operationThread); - // add the operation to the operation thread and start it. - operationThread->add(updateOperation.get()); - operationThread->startThread(); + // create the operation that will run in the background and + // sync once per frame with the main viewer loop. + updateOperation = new UpdateTextOperation(textGroup); - // add the operation to the viewer to sync once per frame. - viewer.addUpdateOperation(updateOperation.get()); + // add the operation to the operation thread and start it. + operationThread->add(updateOperation.get()); + operationThread->startThread(); + + // add the operation to the viewer to sync once per frame. + viewer.addUpdateOperation(updateOperation.get()); - // add a unit cube for the text to appear within. - osg::Geode* geode = new osg::Geode; - geode->getOrCreateStateSet()->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK,osg::PolygonMode::LINE)); - geode->addDrawable(new osg::ShapeDrawable(new osg::Box(center,diameter))); + // add a unit cube for the text to appear within. + osg::Geode* geode = new osg::Geode; + geode->getOrCreateStateSet()->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK,osg::PolygonMode::LINE)); + geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.5f,0.5f,0.5f),1.0))); - mainGroup->addChild(geode); - } - - viewer.setSceneData(mainGroup); + mainGroup->addChild(geode); } - else - { - // prepare scene. - osg::Vec3 center(0.0f,0.0f,0.0f); - float radius = 1.0f; - - // make sure the root node is group so we can add extra nodes to it. - osg::Group* group = new osg::Group; - - { - // create the hud. - osg::Camera* camera = new osg::Camera; - camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); - camera->setProjectionMatrixAsOrtho2D(0,1280,0,1024); - camera->setViewMatrix(osg::Matrix::identity()); - camera->setClearMask(GL_DEPTH_BUFFER_BIT); - camera->addChild(createHUDText()); - camera->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF); - group->addChild(camera); - } - - group->addChild(create3DText(center,radius)); - - // set the scene to render - viewer.setSceneData(group); - } + viewer.setSceneData(mainGroup); + } + #if 0 - osgDB::writeNodeFile(*viewer.getSceneData(),"text.osg"); + osgDB::writeNodeFile(*viewer.getSceneData(),"text.osg"); #endif - viewer.addEventHandler(new osgViewer::StatsHandler()); + viewer.addEventHandler(new osgViewer::StatsHandler()); + viewer.addEventHandler( new osgViewer::ThreadingHandler ); + viewer.addEventHandler( new osgViewer::WindowSizeHandler ); - viewer.run(); - - if (!operationThreads.empty()) + + viewer.run(); + + if (!operationThreads.empty()) + { + for(Threads::iterator itr = operationThreads.begin(); + itr != operationThreads.begin(); + ++itr) { - for(Threads::iterator itr = operationThreads.begin(); - itr != operationThreads.end(); - ++itr) - { - (*itr)->cancel(); - } + (*itr)->cancel(); } + } + + return 0; } diff --git a/include/osgText/Font b/include/osgText/Font index 9c5b31248..312b5de2d 100644 --- a/include/osgText/Font +++ b/include/osgText/Font @@ -158,9 +158,6 @@ public: typedef OpenThreads::Mutex FontMutex; - /** Get the mutex that enables the serialization of calls to this font.*/ - static FontMutex* getSerializeFontCallsMutex(); - protected: virtual ~Font(); @@ -173,13 +170,15 @@ protected: typedef std::map< FontResolution, GlyphMap > FontSizeGlyphMap; + mutable OpenThreads::Mutex _glyphMapMutex; + osg::ref_ptr _texenv; osg::ref_ptr _stateset; FontSizeGlyphMap _sizeGlyphMap; GlyphTextureList _glyphTextureList; // current active size of font - FontResolution _fontSize; + FontResolution _fontSize; unsigned int _margin; float _marginRatio; diff --git a/include/osgText/Font3D b/include/osgText/Font3D index a53afa66f..2ded85516 100644 --- a/include/osgText/Font3D +++ b/include/osgText/Font3D @@ -111,9 +111,6 @@ public: virtual void setThreadSafeRefUnref(bool threadSafe); typedef OpenThreads::Mutex Font3DMutex; - - /** Get the mutex that enables the serialization of calls to this font.*/ - static Font3DMutex* getSerializeFontCallsMutex(); protected: diff --git a/src/osgPlugins/freetype/FreeTypeFont.cpp b/src/osgPlugins/freetype/FreeTypeFont.cpp index 099541945..c727ce220 100644 --- a/src/osgPlugins/freetype/FreeTypeFont.cpp +++ b/src/osgPlugins/freetype/FreeTypeFont.cpp @@ -97,7 +97,7 @@ void FreeTypeFont::setFontResolution(const osgText::FontResolution& fontSize) osgText::Font::Glyph* FreeTypeFont::getGlyph(const osgText::FontResolution& fontRes, unsigned int charcode) { - OpenThreads::ScopedLock lock(_mutex); + OpenThreads::ScopedLock lock(FreeTypeLibrary::instance()->getMutex()); setFontResolution(fontRes); @@ -201,7 +201,7 @@ osgText::Font::Glyph* FreeTypeFont::getGlyph(const osgText::FontResolution& font osg::Vec2 FreeTypeFont::getKerning(const osgText::FontResolution& fontRes, unsigned int leftcharcode,unsigned int rightcharcode, osgText::KerningType kerningType) { - OpenThreads::ScopedLock lock(_mutex); + OpenThreads::ScopedLock lock(FreeTypeLibrary::instance()->getMutex()); if (!FT_HAS_KERNING(_face) || (kerningType == osgText::KERNING_NONE)) return osg::Vec2(0.0f,0.0f); @@ -233,5 +233,6 @@ osg::Vec2 FreeTypeFont::getKerning(const osgText::FontResolution& fontRes, unsig bool FreeTypeFont::hasVertical() const { + OpenThreads::ScopedLock lock(FreeTypeLibrary::instance()->getMutex()); return FT_HAS_VERTICAL(_face)!=0; } diff --git a/src/osgPlugins/freetype/FreeTypeFont.h b/src/osgPlugins/freetype/FreeTypeFont.h index 0191c4de2..f01d94907 100644 --- a/src/osgPlugins/freetype/FreeTypeFont.h +++ b/src/osgPlugins/freetype/FreeTypeFont.h @@ -41,7 +41,6 @@ protected: void setFontResolution(const osgText::FontResolution& fontSize); - OpenThreads::Mutex _mutex; osgText::FontResolution _currentRes; std::string _filename; diff --git a/src/osgPlugins/freetype/FreeTypeLibrary.cpp b/src/osgPlugins/freetype/FreeTypeLibrary.cpp index 842291f03..55b2b40dc 100644 --- a/src/osgPlugins/freetype/FreeTypeLibrary.cpp +++ b/src/osgPlugins/freetype/FreeTypeLibrary.cpp @@ -69,6 +69,8 @@ FreeTypeLibrary* FreeTypeLibrary::instance() bool FreeTypeLibrary::getFace(const std::string& fontfile,unsigned int index, FT_Face & face) { + OpenThreads::ScopedLock lock(getMutex()); + FT_Error error = FT_New_Face( _ftlibrary, fontfile.c_str(), index, &face ); if (error == FT_Err_Unknown_File_Format) { @@ -110,6 +112,8 @@ bool FreeTypeLibrary::getFace(const std::string& fontfile,unsigned int index, FT FT_Byte* FreeTypeLibrary::getFace(std::istream& fontstream, unsigned int index, FT_Face & face) { + OpenThreads::ScopedLock lock(getMutex()); + FT_Open_Args args; std::streampos start = fontstream.tellg(); @@ -159,6 +163,7 @@ osgText::Font* FreeTypeLibrary::getFont(const std::string& fontfile, unsigned in FT_Face face; if (getFace(fontfile, index, face) == false) return (0); + OpenThreads::ScopedLock lock(getMutex()); FreeTypeFont* fontImp = new FreeTypeFont(fontfile,face,flags); osgText::Font* font = new osgText::Font(fontImp); @@ -174,6 +179,8 @@ osgText::Font* FreeTypeLibrary::getFont(std::istream& fontstream, unsigned int i if (face == 0) return (0); + OpenThreads::ScopedLock lock(getMutex()); + FreeTypeFont* fontImp = new FreeTypeFont(buffer,face,flags); osgText::Font* font = new osgText::Font(fontImp); @@ -187,6 +194,7 @@ osgText::Font3D* FreeTypeLibrary::getFont3D(const std::string& fontfile, unsigne FT_Face face; if (getFace(fontfile, index, face) == false) return (0); + OpenThreads::ScopedLock lock(getMutex()); FreeTypeFont3D* font3DImp = new FreeTypeFont3D(fontfile,face,flags); osgText::Font3D* font3D = new osgText::Font3D(font3DImp); @@ -197,11 +205,13 @@ osgText::Font3D* FreeTypeLibrary::getFont3D(const std::string& fontfile, unsigne } osgText::Font3D* FreeTypeLibrary::getFont3D(std::istream& fontstream, unsigned int index, unsigned int flags) { + FT_Face face = 0; FT_Byte * buffer = getFace(fontstream, index, face); if (face == 0) return (0); - + OpenThreads::ScopedLock lock(getMutex()); + FreeTypeFont3D* font3DImp = new FreeTypeFont3D(buffer,face,flags); osgText::Font3D* font3D = new osgText::Font3D(font3DImp); diff --git a/src/osgPlugins/freetype/FreeTypeLibrary.h b/src/osgPlugins/freetype/FreeTypeLibrary.h index e8a26d03f..4e508a808 100644 --- a/src/osgPlugins/freetype/FreeTypeLibrary.h +++ b/src/osgPlugins/freetype/FreeTypeLibrary.h @@ -35,6 +35,8 @@ public: /** get the singleton instance.*/ static FreeTypeLibrary* instance(); + OpenThreads::Mutex& getMutex() { return _mutex; } + osgText::Font* getFont(const std::string& fontfile,unsigned int index=0, unsigned int flags=0); osgText::Font* getFont(std::istream& fontstream, unsigned int index=0, unsigned int flags=0); @@ -61,9 +63,10 @@ protected: typedef std::set< FreeTypeFont* > FontImplementationSet; typedef std::set< FreeTypeFont3D* > Font3DImplementationSet; - FT_Library _ftlibrary; - FontImplementationSet _fontImplementationSet; - Font3DImplementationSet _font3DImplementationSet; + mutable OpenThreads::Mutex _mutex; + FT_Library _ftlibrary; + FontImplementationSet _fontImplementationSet; + Font3DImplementationSet _font3DImplementationSet; }; diff --git a/src/osgText/Font.cpp b/src/osgText/Font.cpp index 9ec7e7f8c..d43de94bc 100644 --- a/src/osgText/Font.cpp +++ b/src/osgText/Font.cpp @@ -32,12 +32,6 @@ static osg::ApplicationUsageProxy Font_e0(osg::ApplicationUsage::ENVIRONMENTAL_V static OpenThreads::ReentrantMutex s_FontFileMutex; -Font::FontMutex* osgText::Font::getSerializeFontCallsMutex() -{ - static OpenThreads::Mutex s_serializeFontCallsMutex; - return &s_serializeFontCallsMutex; -} - std::string osgText::findFontFile(const std::string& str) { // try looking in OSGFILEPATH etc first for fonts. @@ -330,14 +324,17 @@ osg::Texture::FilterMode Font::getMagFilterHint() const Font::Glyph* Font::getGlyph(const FontResolution& fontRes, unsigned int charcode) { - FontSizeGlyphMap::iterator itr = _sizeGlyphMap.find(fontRes); - if (itr!=_sizeGlyphMap.end()) { - GlyphMap& glyphmap = itr->second; - GlyphMap::iterator gitr = glyphmap.find(charcode); - if (gitr!=glyphmap.end()) return gitr->second.get(); + OpenThreads::ScopedLock lock(_glyphMapMutex); + FontSizeGlyphMap::iterator itr = _sizeGlyphMap.find(fontRes); + if (itr!=_sizeGlyphMap.end()) + { + GlyphMap& glyphmap = itr->second; + GlyphMap::iterator gitr = glyphmap.find(charcode); + if (gitr!=glyphmap.end()) return gitr->second.get(); + } } - + if (_implementation.valid()) return _implementation->getGlyph(fontRes, charcode); else return 0; } @@ -400,6 +397,8 @@ bool Font::hasVertical() const void Font::addGlyph(const FontResolution& fontRes, unsigned int charcode, Glyph* glyph) { + OpenThreads::ScopedLock lock(_glyphMapMutex); + _sizeGlyphMap[fontRes][charcode]=glyph; int posX=0,posY=0; diff --git a/src/osgText/Font3D.cpp b/src/osgText/Font3D.cpp index 58f8585cb..3ea4bbfdb 100644 --- a/src/osgText/Font3D.cpp +++ b/src/osgText/Font3D.cpp @@ -37,12 +37,6 @@ static OpenThreads::ReentrantMutex s_Font3DFileMutex; namespace osgText { -Font::FontMutex* Font3D::getSerializeFontCallsMutex() -{ - static OpenThreads::Mutex s_serializeFontCallsMutex; - return &s_serializeFontCallsMutex; -} - std::string findFont3DFile(const std::string& str) { // try looking in OSGFILEPATH etc first for fonts. diff --git a/src/osgText/Text3D.cpp b/src/osgText/Text3D.cpp index 0dd3c34b9..81e031d20 100644 --- a/src/osgText/Text3D.cpp +++ b/src/osgText/Text3D.cpp @@ -224,8 +224,6 @@ void Text3D::computeGlyphRepresentation() return; } - OpenThreads::ScopedLock lock(*(_font->getSerializeFontCallsMutex())); - // initialize bounding box, it will be expanded during glyph position calculation _textBB.init();