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