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