root/OpenSceneGraph/trunk/examples/osgtext/osgtext.cpp @ 7874

Revision 7874, 6.9 kB (checked in by robert, 6 years ago)

Refactored the mutex usage in osgText and freetype plugin to prevent multi-thread crash

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* OpenSceneGraph example, osgtext.
2*
3*  Permission is hereby granted, free of charge, to any person obtaining a copy
4*  of this software and associated documentation files (the "Software"), to deal
5*  in the Software without restriction, including without limitation the rights
6*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7*  copies of the Software, and to permit persons to whom the Software is
8*  furnished to do so, subject to the following conditions:
9*
10*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16*  THE SOFTWARE.
17*/
18
19#include <osgUtil/Optimizer>
20
21#include <osgDB/ReadFile>
22#include <osgDB/WriteFile>
23#include <osgDB/Registry>
24
25#include <osgViewer/Viewer>
26#include <osgViewer/ViewerEventHandlers>
27
28#include <osg/Geode>
29#include <osg/Camera>
30#include <osg/ShapeDrawable>
31#include <osg/Sequence>
32#include <osg/PolygonMode>
33#include <osg/io_utils>
34
35#include <osgText/Font>
36#include <osgText/Text>
37
38
39
40
41
42
43
44class UpdateTextOperation : public osg::Operation
45{
46public:
47
48  UpdateTextOperation(osg::Group* group):       
49      Operation("UpdateTextOperation", true),
50        _group(group),
51        _maxNumChildren(200),
52        _maxNumTextPerGeode(10)
53      {
54      }
55
56      virtual void operator () (osg::Object* callingObject)
57      {
58        // decided which method to call according to whole has called me.
59        osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(callingObject);
60
61        if (viewer) update();
62        else load();
63      }
64
65      void update()
66      {
67        // osg::notify(osg::NOTICE)<<"*** Doing update"<<std::endl;
68
69        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
70
71        if (_mergeSubgraph.valid())
72        {
73          _group->addChild(_mergeSubgraph.get());
74
75          _mergeSubgraph = 0;
76
77          if (_group->getNumChildren()>_maxNumChildren)
78          {
79            osg::Geode* geode = dynamic_cast<osg::Geode*>(_group->getChild(0));
80            if (geode)
81            {
82              _availableSubgraph.push_back(geode);
83              geode->removeDrawables(0,geode->getNumDrawables());
84            }
85            _group->removeChild(0,1);
86          }
87
88          _waitOnMergeBlock.release();
89        }       
90      }
91
92      void load()
93      {
94
95        // osg::notify(osg::NOTICE)<<"Doing load"<<std::endl;
96
97        osg::ref_ptr<osg::Geode> geode;
98        {
99          OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
100          if (!_availableSubgraph.empty())
101          {
102            geode = _availableSubgraph.front();
103            _availableSubgraph.pop_front();
104          }
105        }
106
107        if (!geode) geode = new osg::Geode;
108
109        for(unsigned int i=0; i<_maxNumTextPerGeode; ++i)
110        {
111          osg::Vec3 position(float(rand()) / float(RAND_MAX), float(rand()) / float(RAND_MAX), float(i)/float(_maxNumTextPerGeode));
112
113          std::string str;
114          unsigned int _numCharacters = 5;
115          for(unsigned int ni=0; ni<_numCharacters;++ni)
116          {
117            str.push_back(char(32.0 + (float(rand())/float(RAND_MAX))*128.0f));
118          }
119
120          osgText::Text* text = new osgText::Text;
121          text->setDataVariance(osg::Object::DYNAMIC);
122          text->setPosition(position);
123          text->setFont("times.ttf");
124          text->setText(str);
125          text->setCharacterSize(0.025f);
126          text->setAxisAlignment(osgText::Text::SCREEN);
127
128          geode->addDrawable(text);
129        }
130
131
132        {       
133          OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
134          _mergeSubgraph = geode;
135        }
136
137        // osg::notify(osg::NOTICE)<<"Waiting on merge"<<std::endl;
138
139        _waitOnMergeBlock.block();
140
141      }
142
143      virtual void release()
144      {
145        _waitOnMergeBlock.release();
146      }
147
148      typedef std::list< osg::ref_ptr<osg::Geode> > AvailableList;
149
150      unsigned int                _maxNumChildren;
151      unsigned int                _maxNumTextPerGeode;
152
153      OpenThreads::Mutex          _mutex;
154      osg::ref_ptr<osg::Group>    _group;
155      osg::ref_ptr<osg::Geode>    _mergeSubgraph;
156      AvailableList               _availableSubgraph;
157      OpenThreads::Block          _waitOnMergeBlock;
158
159      unsigned int                _counter;
160
161};
162
163
164int main(int argc, char** argv)
165{
166  osg::ArgumentParser arguments(&argc, argv);
167
168
169  osg::Referenced::setThreadSafeReferenceCounting(true);
170
171  // construct the viewer.
172  osgViewer::Viewer viewer(arguments);
173
174  typedef std::list< osg::ref_ptr<osg::OperationThread> > Threads;
175
176  Threads operationThreads;
177  osg::ref_ptr<UpdateTextOperation> updateOperation;
178
179  unsigned int numThreads = 0;
180  if (arguments.read("--mt", numThreads) || arguments.read("--mt"))
181  {
182    // construct a multi-threaded text updating test.
183    if (numThreads==0) numThreads = 1;
184
185    // create a group to add everything into.
186    osg::Group* mainGroup = new osg::Group;
187
188    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
189    mainGroup->addChild(loadedModel.get());
190
191    for(unsigned int i=0; i<numThreads; ++i)
192    {
193      osg::Group* textGroup = new osg::Group;
194      mainGroup->addChild(textGroup);
195
196      // create the background thread
197      osg::OperationThread* operationThread = new osg::OperationThread;
198
199      operationThreads.push_back(operationThread);
200
201      // create the operation that will run in the background and
202      // sync once per frame with the main viewer loop.
203      updateOperation = new UpdateTextOperation(textGroup);
204
205      // add the operation to the operation thread and start it.
206      operationThread->add(updateOperation.get());
207      operationThread->startThread();
208
209      // add the operation to the viewer to sync once per frame.
210      viewer.addUpdateOperation(updateOperation.get());
211
212
213      // add a unit cube for the text to appear within.
214      osg::Geode* geode = new osg::Geode;
215      geode->getOrCreateStateSet()->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK,osg::PolygonMode::LINE));
216      geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.5f,0.5f,0.5f),1.0)));
217
218      mainGroup->addChild(geode);
219    }
220
221    viewer.setSceneData(mainGroup);       
222  }
223 
224
225#if 0
226  osgDB::writeNodeFile(*viewer.getSceneData(),"text.osg");
227#endif
228
229  viewer.addEventHandler(new osgViewer::StatsHandler());
230  viewer.addEventHandler( new osgViewer::ThreadingHandler );
231  viewer.addEventHandler( new osgViewer::WindowSizeHandler );
232
233
234  viewer.run();
235
236  if (!operationThreads.empty())
237  {
238    for(Threads::iterator itr = operationThreads.begin();
239      itr != operationThreads.begin();
240      ++itr)
241    {
242      (*itr)->cancel();
243    }
244  }
245
246  return 0;
247}
Note: See TracBrowser for help on using the browser.