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 <osgGA/StateSetManipulator>
26 #include <osgViewer/Viewer>
27 #include <osgViewer/ViewerEventHandlers>
28 
29 #include <osg/Geode>
30 #include <osg/Camera>
31 #include <osg/ShapeDrawable>
32 #include <osg/Sequence>
33 #include <osg/PolygonMode>
34 #include <osg/io_utils>
35 
36 #include <osgText/Font>
37 #include <osgText/Text>
38 
createHUDText()39 osg::Group* createHUDText()
40 {
41 
42     osg::Group* rootNode = new osg::Group;
43 
44     osg::ref_ptr<osgText::Font> font = osgText::readRefFontFile("fonts/arial.ttf");
45 
46     //osg::setNotifyLevel(osg::INFO);
47 
48     osg::Geode* geode  = new osg::Geode;
49     rootNode->addChild(geode);
50 
51     float windowHeight = 1024.0f;
52     float windowWidth = 1280.0f;
53     float margin = 50.0f;
54 
55 ////////////////////////////////////////////////////////////////////////////////////////////////////////
56 //
57 // Examples of how to set up different text layout
58 //
59 
60     osg::Vec4 layoutColor(1.0f,1.0f,0.0f,1.0f);
61     float layoutCharacterSize = 20.0f;
62 
63     {
64         osgText::Text* text = new osgText::Text;
65         text->setFont(font);
66         text->setColor(layoutColor);
67         text->setCharacterSize(layoutCharacterSize);
68         text->setPosition(osg::Vec3(margin,windowHeight-margin,0.0f));
69 
70         // the default layout is left to right, typically used in languages
71         // originating from europe such as English, French, German, Spanish etc..
72         text->setLayout(osgText::Text::LEFT_TO_RIGHT);
73 
74         text->setText("text->setLayout(osgText::Text::LEFT_TO_RIGHT);");
75         geode->addDrawable(text);
76     }
77 
78     {
79         osgText::Text* text = new osgText::Text;
80         text->setFont(font);
81         text->setColor(layoutColor);
82         text->setCharacterSize(layoutCharacterSize);
83         text->setPosition(osg::Vec3(windowWidth-margin,windowHeight-margin,0.0f));
84 
85         // right to left layouts would be used for hebrew or arabic fonts.
86         text->setLayout(osgText::Text::RIGHT_TO_LEFT);
87         text->setAlignment(osgText::Text::RIGHT_BASE_LINE);
88 
89         text->setText("text->setLayout(osgText::Text::RIGHT_TO_LEFT);");
90         geode->addDrawable(text);
91     }
92 
93     {
94         osgText::Text* text = new osgText::Text;
95         text->setFont(font);
96         text->setColor(layoutColor);
97         text->setPosition(osg::Vec3(margin,windowHeight-margin,0.0f));
98         text->setCharacterSize(layoutCharacterSize);
99 
100         // vertical font layout would be used for asian fonts.
101         text->setLayout(osgText::Text::VERTICAL);
102 
103         text->setText("text->setLayout(osgText::Text::VERTICAL);");
104         geode->addDrawable(text);
105     }
106 
107 
108 ////////////////////////////////////////////////////////////////////////////////////////////////////////
109 //
110 // Examples of how to set up different font resolution
111 //
112 
113     osg::Vec4 fontSizeColor(0.0f,1.0f,1.0f,1.0f);
114     float fontSizeCharacterSize = 30;
115 
116     osg::Vec3 cursor = osg::Vec3(margin*2,windowHeight-margin*2,0.0f);
117 
118     {
119         osgText::Text* text = new osgText::Text;
120         text->setFont(font);
121         text->setColor(fontSizeColor);
122         text->setCharacterSize(fontSizeCharacterSize);
123         text->setPosition(cursor);
124 
125         // use text that uses 10 by 10 texels as a target resolution for fonts.
126         text->setFontResolution(10,10); // blocky but small texture memory usage
127 
128         text->setText("text->setFontResolution(10,10); // blocky but small texture memory usage");
129         geode->addDrawable(text);
130     }
131 
132     cursor.y() -= fontSizeCharacterSize;
133     {
134         osgText::Text* text = new osgText::Text;
135         text->setFont(font);
136         text->setColor(fontSizeColor);
137         text->setCharacterSize(fontSizeCharacterSize);
138         text->setPosition(cursor);
139 
140         // use text that uses 20 by 20 texels as a target resolution for fonts.
141         text->setFontResolution(20,20); // smoother but higher texture memory usage (but still quite low).
142 
143         text->setText("text->setFontResolution(20,20); // smoother but higher texture memory usage (but still quite low).");
144         geode->addDrawable(text);
145     }
146 
147     cursor.y() -= fontSizeCharacterSize;
148     {
149         osgText::Text* text = new osgText::Text;
150         text->setFont(font);
151         text->setColor(fontSizeColor);
152         text->setCharacterSize(fontSizeCharacterSize);
153         text->setPosition(cursor);
154 
155         // use text that uses 40 by 40 texels as a target resolution for fonts.
156         text->setFontResolution(40,40); // even smoother but again higher texture memory usage.
157 
158         text->setText("text->setFontResolution(40,40); // even smoother but again higher texture memory usage.");
159         geode->addDrawable(text);
160     }
161 
162 
163 ////////////////////////////////////////////////////////////////////////////////////////////////////////
164 //
165 // Examples of how to set up different sized text
166 //
167 
168     osg::Vec4 characterSizeColor(1.0f,0.0f,1.0f,1.0f);
169 
170     cursor.y() -= fontSizeCharacterSize*2.0f;
171 
172     {
173         osgText::Text* text = new osgText::Text;
174         text->setFont(font);
175         text->setColor(characterSizeColor);
176         text->setFontResolution(20,20);
177         text->setPosition(cursor);
178 
179         // use text that is 20 units high.
180         text->setCharacterSize(20); // small
181 
182         text->setText("text->setCharacterSize(20.0f); // small");
183         geode->addDrawable(text);
184     }
185 
186     cursor.y() -= 30.0f;
187     {
188         osgText::Text* text = new osgText::Text;
189         text->setFont(font);
190         text->setColor(characterSizeColor);
191         text->setFontResolution(30,30);
192         text->setPosition(cursor);
193 
194         // use text that is 30 units high.
195         text->setCharacterSize(30.0f); // medium
196 
197         text->setText("text->setCharacterSize(30.0f); // medium");
198         geode->addDrawable(text);
199     }
200 
201     cursor.y() -= 50.0f;
202     {
203         osgText::Text* text = new osgText::Text;
204         text->setFont(font);
205         text->setColor(characterSizeColor);
206         text->setFontResolution(40,40);
207         text->setPosition(cursor);
208 
209         // use text that is 60 units high.
210         text->setCharacterSize(60.0f); // large
211 
212         text->setText("text->setCharacterSize(60.0f); // large");
213         geode->addDrawable(text);
214     }
215 
216 
217 ////////////////////////////////////////////////////////////////////////////////////////////////////////
218 //
219 // Examples of how to set up different alignments
220 //
221 
222     osg::Vec4 alignmentSizeColor(0.0f,1.0f,0.0f,1.0f);
223     float alignmentCharacterSize = 25.0f;
224     cursor.x() = 640;
225     cursor.y() = margin*4.0f;
226 
227     typedef std::pair<osgText::Text::AlignmentType,std::string> AlignmentPair;
228     typedef std::vector<AlignmentPair> AlignmentList;
229     AlignmentList alignmentList;
230     alignmentList.push_back(AlignmentPair(osgText::Text::LEFT_TOP,"text->setAlignment(\nosgText::Text::LEFT_TOP);"));
231     alignmentList.push_back(AlignmentPair(osgText::Text::LEFT_CENTER,"text->setAlignment(\nosgText::Text::LEFT_CENTER);"));
232     alignmentList.push_back(AlignmentPair(osgText::Text::LEFT_BOTTOM,"text->setAlignment(\nosgText::Text::LEFT_BOTTOM);"));
233     alignmentList.push_back(AlignmentPair(osgText::Text::CENTER_TOP,"text->setAlignment(\nosgText::Text::CENTER_TOP);"));
234     alignmentList.push_back(AlignmentPair(osgText::Text::CENTER_CENTER,"text->setAlignment(\nosgText::Text::CENTER_CENTER);"));
235     alignmentList.push_back(AlignmentPair(osgText::Text::CENTER_BOTTOM,"text->setAlignment(\nosgText::Text::CENTER_BOTTOM);"));
236     alignmentList.push_back(AlignmentPair(osgText::Text::RIGHT_TOP,"text->setAlignment(\nosgText::Text::RIGHT_TOP);"));
237     alignmentList.push_back(AlignmentPair(osgText::Text::RIGHT_CENTER,"text->setAlignment(\nosgText::Text::RIGHT_CENTER);"));
238     alignmentList.push_back(AlignmentPair(osgText::Text::RIGHT_BOTTOM,"text->setAlignment(\nosgText::Text::RIGHT_BOTTOM);"));
239     alignmentList.push_back(AlignmentPair(osgText::Text::LEFT_BASE_LINE,"text->setAlignment(\nosgText::Text::LEFT_BASE_LINE);"));
240     alignmentList.push_back(AlignmentPair(osgText::Text::CENTER_BASE_LINE,"text->setAlignment(\nosgText::Text::CENTER_BASE_LINE);"));
241     alignmentList.push_back(AlignmentPair(osgText::Text::RIGHT_BASE_LINE,"text->setAlignment(\nosgText::Text::RIGHT_BASE_LINE);"));
242     alignmentList.push_back(AlignmentPair(osgText::Text::LEFT_BOTTOM_BASE_LINE,"text->setAlignment(\nosgText::Text::LEFT_BOTTOM_BASE_LINE);"));
243     alignmentList.push_back(AlignmentPair(osgText::Text::CENTER_BOTTOM_BASE_LINE,"text->setAlignment(\nosgText::Text::CENTER_BOTTOM_BASE_LINE);"));
244     alignmentList.push_back(AlignmentPair(osgText::Text::RIGHT_BOTTOM_BASE_LINE,"text->setAlignment(\nosgText::Text::RIGHT_BOTTOM_BASE_LINE);"));
245 
246 
247     osg::Sequence* sequence = new osg::Sequence;
248     {
249         for(AlignmentList::iterator itr=alignmentList.begin();
250             itr!=alignmentList.end();
251             ++itr)
252         {
253             osg::Geode* alignmentGeode = new osg::Geode;
254             sequence->addChild(alignmentGeode);
255             sequence->setTime(sequence->getNumChildren(), 1.0f);
256 
257             osgText::Text* text = new osgText::Text;
258             text->setFont(font);
259             text->setColor(alignmentSizeColor);
260             text->setCharacterSize(alignmentCharacterSize);
261             text->setPosition(cursor);
262             text->setDrawMode(osgText::Text::TEXT|osgText::Text::ALIGNMENT|osgText::Text::BOUNDINGBOX);
263 
264             text->setAlignment(itr->first);
265             text->setText(itr->second);
266 
267             alignmentGeode->addDrawable(text);
268 
269 
270         }
271 
272     }
273 
274     sequence->setMode(osg::Sequence::START);
275     sequence->setInterval(osg::Sequence::LOOP, 0, -1);
276     sequence->setDuration(1.0f, -1);
277 
278     rootNode->addChild(sequence);
279 
280 
281 ////////////////////////////////////////////////////////////////////////////////////////////////////////
282 //
283 // Examples of how to set up different fonts...
284 //
285 
286     cursor.x() = margin*2.0f;
287     cursor.y() = margin*2.0f;
288 
289     osg::Vec4 fontColor(1.0f,0.5f,0.0f,1.0f);
290     float fontCharacterSize = 20.0f;
291     float spacing = 40.0f;
292 
293     {
294         osg::ref_ptr<osgText::Text> text = new osgText::Text;
295         text->setColor(fontColor);
296         text->setPosition(cursor);
297         text->setCharacterSize(fontCharacterSize);
298 
299         text->setFont(0);
300         text->setText("text->setFont(0); // inbuilt font.");
301         geode->addDrawable(text);
302 
303         cursor.x() = text->getBoundingBox().xMax() + spacing ;
304     }
305 
306     {
307         osg::ref_ptr<osgText::Font> arial = osgText::readRefFontFile("fonts/arial.ttf");
308 
309         osg::ref_ptr<osgText::Text> text = new osgText::Text;
310         text->setColor(fontColor);
311         text->setPosition(cursor);
312         text->setCharacterSize(fontCharacterSize);
313 
314         text->setFont(arial);
315         text->setText(arial!=0?
316                       "text->setFont(\"fonts/arial.ttf\");":
317                       "unable to load \"fonts/arial.ttf\"");
318         geode->addDrawable(text);
319 
320         cursor.x() = text->getBoundingBox().xMax() + spacing ;
321     }
322 
323     {
324         osg::ref_ptr<osgText::Font> times = osgText::readRefFontFile("fonts/times.ttf");
325 
326         osg::ref_ptr<osgText::Text> text = new osgText::Text;
327         text->setColor(fontColor);
328         text->setPosition(cursor);
329         text->setCharacterSize(fontCharacterSize);
330 
331         geode->addDrawable(text);
332         text->setFont(times);
333         text->setText(times!=0?
334                       "text->setFont(\"fonts/times.ttf\");":
335                       "unable to load \"fonts/times.ttf\"");
336 
337         cursor.x() = text->getBoundingBox().xMax() + spacing ;
338     }
339 
340     cursor.x() = margin*2.0f;
341     cursor.y() = margin;
342 
343     {
344         osg::ref_ptr<osgText::Font> dirtydoz = osgText::readRefFontFile("fonts/dirtydoz.ttf");
345 
346         osg::ref_ptr<osgText::Text> text = new osgText::Text;
347         text->setColor(fontColor);
348         text->setPosition(cursor);
349         text->setCharacterSize(fontCharacterSize);
350 
351         text->setFont(dirtydoz);
352         text->setText(dirtydoz!=0?
353                       "text->setFont(\"fonts/dirtydoz.ttf\");":
354                       "unable to load \"fonts/dirtydoz.ttf\"");
355         geode->addDrawable(text);
356 
357         cursor.x() = text->getBoundingBox().xMax() + spacing ;
358     }
359 
360     {
361         osg::ref_ptr<osgText::Font> fudd = osgText::readRefFontFile("fonts/fudd.ttf");
362 
363         osg::ref_ptr<osgText::Text> text = new osgText::Text;
364         text->setColor(fontColor);
365         text->setPosition(cursor);
366         text->setCharacterSize(fontCharacterSize);
367 
368         text->setFont(fudd);
369         text->setText(fudd!=0?
370                       "text->setFont(\"fonts/fudd.ttf\");":
371                       "unable to load \"fonts/fudd.ttf\"");
372         geode->addDrawable(text);
373 
374         cursor.x() = text->getBoundingBox().xMax() + spacing ;
375     }
376 
377     return rootNode;
378 }
379 
380 
381 
382 
383 // create text which sits in 3D space such as would be inserted into a normal model
create3DText(const osg::Vec3 & center,float radius)384 osg::Group* create3DText(const osg::Vec3& center,float radius)
385 {
386 
387     osg::Geode* geode  = new osg::Geode;
388 
389 ////////////////////////////////////////////////////////////////////////////////////////////////////////
390 //
391 // Examples of how to set up axis/orientation alignments
392 //
393 
394     float characterSize=radius*0.2f;
395 
396 
397     osg::Vec3 pos(center.x()-radius*.5f,center.y()-radius*.5f,center.z()-radius*.5f);
398 
399     osgText::Text* text1 = new osgText::Text;
400     text1->setFont("fonts/times.ttf");
401     text1->setCharacterSize(characterSize);
402     text1->setPosition(pos);
403     text1->setAxisAlignment(osgText::Text::XY_PLANE);
404     text1->setText("XY_PLANE");
405     geode->addDrawable(text1);
406 
407     osgText::Text* text2 = new osgText::Text;
408     text2->setFont("fonts/times.ttf");
409     text2->setCharacterSize(characterSize);
410     text2->setPosition(pos);
411     text2->setAxisAlignment(osgText::Text::YZ_PLANE);
412     text2->setText("YZ_PLANE");
413     geode->addDrawable(text2);
414 
415     osgText::Text* text3 = new osgText::Text;
416     text3->setFont("fonts/times.ttf");
417     text3->setCharacterSize(characterSize);
418     text3->setPosition(pos);
419     text3->setAxisAlignment(osgText::Text::XZ_PLANE);
420     text3->setText("XZ_PLANE");
421     geode->addDrawable(text3);
422 
423     osg::Vec4 characterSizeModeColor(1.0f,0.0f,0.5f,1.0f);
424 
425     osgText::Text* text4 = new osgText::Text;
426     text4->setFont("fonts/times.ttf");
427     text4->setCharacterSize(characterSize);
428     text4->setPosition(center);
429     text4->setAxisAlignment(osgText::Text::SCREEN);
430 
431     // reproduce outline bounding box compute problem with backdrop on.
432     text4->setBackdropType(osgText::Text::OUTLINE);
433     text4->setDrawMode(osgText::Text::TEXT | osgText::Text::BOUNDINGBOX);
434 
435     text4->setText("SCREEN");
436     geode->addDrawable(text4);
437 
438     osgText::Text* text5 = new osgText::Text;
439     text5->setColor(characterSizeModeColor);
440     text5->setFont("fonts/times.ttf");
441     //text5->setCharacterSize(characterSize);
442     text5->setCharacterSize(32.0f); // medium
443     text5->setPosition(center - osg::Vec3(0.0, 0.0, 0.2) * radius);
444     text5->setAxisAlignment(osgText::Text::SCREEN);
445     text5->setCharacterSizeMode(osgText::Text::SCREEN_COORDS);
446     text5->setDrawMode(osgText::Text::TEXT | osgText::Text::BOUNDINGBOX);
447     text5->setText("CharacterSizeMode SCREEN_COORDS(size 32.0)");
448     geode->addDrawable(text5);
449 
450     osgText::Text* text6 = new osgText::Text;
451     text6->setColor(characterSizeModeColor);
452     text6->setFont("fonts/times.ttf");
453     text6->setCharacterSize(characterSize);
454     text6->setPosition(center - osg::Vec3(0.0, 0.0, 0.4) * radius);
455     text6->setAxisAlignment(osgText::Text::SCREEN);
456     text6->setCharacterSizeMode(osgText::Text::OBJECT_COORDS_WITH_MAXIMUM_SCREEN_SIZE_CAPPED_BY_FONT_HEIGHT);
457     text6->setText("CharacterSizeMode OBJECT_COORDS_WITH_MAXIMUM_SCREEN_SIZE_CAPPED_BY_FONT_HEIGHT");
458     geode->addDrawable(text6);
459 
460     osgText::Text* text7 = new osgText::Text;
461     text7->setColor(characterSizeModeColor);
462     text7->setFont("fonts/times.ttf");
463     text7->setCharacterSize(characterSize);
464     text7->setPosition(center - osg::Vec3(0.0, 0.0, 0.6) * radius);
465     text7->setAxisAlignment(osgText::Text::SCREEN);
466     text7->setCharacterSizeMode(osgText::Text::OBJECT_COORDS);
467     text7->setText("CharacterSizeMode OBJECT_COORDS (default)");
468     geode->addDrawable(text7);
469 
470 
471 #if 0
472     osg::ShapeDrawable* shape = new osg::ShapeDrawable(new osg::Sphere(center,characterSize*0.2f));
473     shape->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::ON);
474     geode->addDrawable(shape);
475 #endif
476 
477     osg::Group* rootNode = new osg::Group;
478     rootNode->addChild(geode);
479 
480     return rootNode;
481 }
482 
483 class UpdateTextOperation : public osg::Operation
484 {
485 public:
486 
UpdateTextOperation(const osg::Vec3 & center,float diameter,osg::Group * group)487     UpdateTextOperation(const osg::Vec3& center, float diameter, osg::Group* group):
488         osg::Referenced(true),
489         Operation("UpdateTextOperation", true),
490         _center(center),
491         _diameter(diameter),
492         _maxNumChildren(200),
493         _maxNumTextPerGeode(10),
494         _group(group)
495     {
496     }
497 
operator ()(osg::Object * callingObject)498     virtual void operator () (osg::Object* callingObject)
499     {
500         // decided which method to call according to whole has called me.
501         osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(callingObject);
502 
503         if (viewer) update();
504         else load();
505     }
506 
update()507     void update()
508     {
509         // osg::notify(osg::NOTICE)<<"*** Doing update"<<std::endl;
510 
511         OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
512 
513         if (_mergeSubgraph.valid())
514         {
515             _group->addChild(_mergeSubgraph.get());
516 
517             _mergeSubgraph = 0;
518 
519             if (_group->getNumChildren()>_maxNumChildren)
520             {
521                 osg::Geode* geode = dynamic_cast<osg::Geode*>(_group->getChild(0));
522                 if (geode)
523                 {
524                     _availableSubgraph.push_back(geode);
525                     geode->removeDrawables(0,geode->getNumDrawables());
526                 }
527                 _group->removeChild(0,1);
528             }
529 
530             _waitOnMergeBlock.release();
531         }
532     }
533 
load()534     void load()
535     {
536 
537         // osg::notify(osg::NOTICE)<<"Doing load"<<std::endl;
538 
539         osg::ref_ptr<osg::Geode> geode;
540         {
541             OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
542             if (!_availableSubgraph.empty())
543             {
544                 geode = _availableSubgraph.front();
545                 _availableSubgraph.pop_front();
546             }
547         }
548 
549         if (!geode) geode = new osg::Geode;
550 
551         for(unsigned int i=0; i<_maxNumTextPerGeode; ++i)
552         {
553             float x = float(rand()) / float(RAND_MAX) - 0.5f;
554             float y = float(rand()) / float(RAND_MAX) - 0.5f;
555             float z = float(i)      / float(_maxNumTextPerGeode) - 0.5f;
556             osg::Vec3 position(x, y, z);
557 
558             std::string str;
559             unsigned int _numCharacters = 5;
560             for(unsigned int ni=0; ni<_numCharacters;++ni)
561             {
562                 str.push_back(char(32.0 + (float(rand())/float(RAND_MAX))*128.0f));
563             }
564 
565             osgText::Text* text = new osgText::Text;
566             text->setDataVariance(osg::Object::DYNAMIC);
567             text->setPosition(_center + position * _diameter);
568             text->setFont("times.ttf");
569             text->setText(str);
570             text->setCharacterSize(0.025f * _diameter);
571             text->setAxisAlignment(osgText::Text::SCREEN);
572 
573             geode->addDrawable(text);
574         }
575 
576 
577         {
578             OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
579             _mergeSubgraph = geode;
580         }
581 
582         // osg::notify(osg::NOTICE)<<"Waiting on merge"<<std::endl;
583 
584         _waitOnMergeBlock.block();
585 
586     }
587 
release()588     virtual void release()
589     {
590         _waitOnMergeBlock.release();
591     }
592 
593     typedef std::list< osg::ref_ptr<osg::Geode> > AvailableList;
594 
595     osg::Vec3                   _center;
596     float                       _diameter;
597     unsigned int                _maxNumChildren;
598     unsigned int                _maxNumTextPerGeode;
599 
600     OpenThreads::Mutex          _mutex;
601     osg::ref_ptr<osg::Group>    _group;
602     osg::ref_ptr<osg::Geode>    _mergeSubgraph;
603     AvailableList               _availableSubgraph;
604     OpenThreads::Block          _waitOnMergeBlock;
605 
606     unsigned int                _counter;
607 
608 };
609 
610 
611 struct TextCounterCallback : public osg::NodeCallback
612 {
613     unsigned int _textCounter;
614 
TextCounterCallbackTextCounterCallback615     TextCounterCallback():
616         _textCounter(100000) {}
617 
operator ()TextCounterCallback618     virtual void operator()(osg::Node* node, osg::NodeVisitor*)
619     {
620         osgText::Text* text = dynamic_cast<osgText::Text*>(node);
621         if (text)
622         {
623             std::stringstream str;
624             str <<"Text Counter "<<_textCounter;
625             OSG_NOTICE<<"Updating text : "<<str.str()<<std::endl;
626 
627             text->setText(str.str());
628 
629             ++_textCounter;
630         }
631     }
632 };
633 
634 
main(int argc,char ** argv)635 int main(int argc, char** argv)
636 {
637     osg::ArgumentParser arguments(&argc, argv);
638 
639     // construct the viewer.
640     osgViewer::Viewer viewer(arguments);
641 
642     typedef std::list< osg::ref_ptr<osg::OperationThread> > Threads;
643 
644     Threads operationThreads;
645     osg::ref_ptr<UpdateTextOperation> updateOperation;
646     unsigned int numThreads = 0;
647 
648     if (arguments.read("--simple"))
649     {
650         osg::ref_ptr<osgText::Text> text = new osgText::Text;
651         text->setFont("fonts/times.ttf");
652         text->setAxisAlignment(osgText::Text::XZ_PLANE);
653         text->setDrawMode(osgText::Text::TEXT|osgText::Text::ALIGNMENT|osgText::Text::BOUNDINGBOX|osgText::Text::FILLEDBOUNDINGBOX);
654         text->setText("This is a simple test");
655 
656         viewer.setSceneData(text.get());
657     }
658     else if (arguments.read("--plain"))
659     {
660         osg::ref_ptr<osgText::Text> text = new osgText::Text;
661         text->setFont("fonts/times.ttf");
662         text->setAxisAlignment(osgText::Text::XZ_PLANE);
663         text->setText("This is a plain test");
664 
665         viewer.setSceneData(text.get());
666     }
667     else if (arguments.read("--counter"))
668     {
669         osg::ref_ptr<osgText::Text> text = new osgText::Text;
670         text->setUpdateCallback(new TextCounterCallback());
671         text->setFont("fonts/times.ttf");
672         text->setAxisAlignment(osgText::Text::XZ_PLANE);
673         text->setText("Text Counter :");
674 
675         viewer.setSceneData(text.get());
676     }
677     else if (arguments.read("--alignment"))
678     {
679         osg::ref_ptr<osg::Group> group = new osg::Group;
680 
681         {
682             osg::ref_ptr<osgText::Text> text = new osgText::Text;
683             text->setFont("fonts/times.ttf");
684             text->setAxisAlignment(osgText::Text::XZ_PLANE);
685             text->setAlignment(osgText::Text::RIGHT_TOP);
686             text->setText("Alingment\nBefore:");
687             group->addChild(text);
688         }
689 
690         {
691             osg::ref_ptr<osgText::Text> text = new osgText::Text;
692             text->setFont("fonts/times.ttf");
693             text->setAxisAlignment(osgText::Text::XZ_PLANE);
694             text->setText("Alingment\nAfter:");
695             text->setAlignment(osgText::Text::LEFT_TOP);
696             group->addChild(text);
697         }
698 
699         viewer.setSceneData(group.get());
700     }
701     else if (arguments.read("--mt", numThreads) || arguments.read("--mt"))
702     {
703         // construct a multi-threaded text updating test.
704         if (numThreads==0) numThreads = 1;
705 
706         // create a group to add everything into.
707         osg::Group* mainGroup = new osg::Group;
708 
709         osg::Vec3 center(0.5f,0.5f,0.5f);
710         float diameter = 1.0f;
711 
712         osg::ref_ptr<osg::Node> loadedModel = osgDB::readRefNodeFiles(arguments);
713         if (loadedModel.valid())
714         {
715             mainGroup->addChild(loadedModel);
716 
717             center = loadedModel->getBound().center();
718             diameter = loadedModel->getBound().radius() * 2.0f;
719         }
720 
721         for(unsigned int i=0; i<numThreads; ++i)
722         {
723             osg::Group* textGroup = new osg::Group;
724             mainGroup->addChild(textGroup);
725 
726             // create the background thread
727             osg::OperationThread* operationThread = new osg::OperationThread;
728 
729             operationThreads.push_back(operationThread);
730 
731             // create the operation that will run in the background and
732             // sync once per frame with the main viewer loop.
733             updateOperation = new UpdateTextOperation(center, diameter, textGroup);
734 
735             // add the operation to the operation thread and start it.
736             operationThread->add(updateOperation.get());
737             operationThread->startThread();
738 
739             // add the operation to the viewer to sync once per frame.
740             viewer.addUpdateOperation(updateOperation.get());
741 
742 
743             // add a unit cube for the text to appear within.
744             osg::Geode* geode = new osg::Geode;
745             geode->getOrCreateStateSet()->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK,osg::PolygonMode::LINE));
746             geode->addDrawable(new osg::ShapeDrawable(new osg::Box(center,diameter)));
747 
748             mainGroup->addChild(geode);
749         }
750 
751         viewer.setSceneData(mainGroup);
752     }
753     else
754     {
755         // prepare scene.
756         osg::Vec3 center(0.0f,0.0f,0.0f);
757         float radius = 100.0f;
758 
759         // make sure the root node is group so we can add extra nodes to it.
760         osg::Group* group = new osg::Group;
761 
762         if (true)
763         {
764             // create the hud.
765             osg::Camera* camera = new osg::Camera;
766             camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
767             camera->setProjectionMatrixAsOrtho2D(0,1280,0,1024);
768             camera->setViewMatrix(osg::Matrix::identity());
769             camera->setClearMask(GL_DEPTH_BUFFER_BIT);
770             camera->addChild(createHUDText());
771             camera->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
772 
773             group->addChild(camera);
774         }
775 
776         if (true)
777         {
778             group->addChild(create3DText(center,radius));
779         }
780 
781         // set the scene to render
782         viewer.setSceneData(group);
783     }
784 
785     std::string filename;
786     if (arguments.read("-o",filename))
787     {
788         osgDB::writeNodeFile(*viewer.getSceneData(),filename);
789         return 0;
790     }
791 
792     viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
793     viewer.addEventHandler(new osgViewer::StatsHandler());
794 
795     viewer.run();
796 
797     if (!operationThreads.empty())
798     {
799         for(Threads::iterator itr = operationThreads.begin();
800             itr != operationThreads.end();
801             ++itr)
802         {
803             (*itr)->cancel();
804         }
805     }
806 
807     return 0;
808 }
809 
810