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 <QApplication>
20 #include <QGridLayout>
21 #include <QWidget>
22 
23 #include <osgQt/GraphicsWindowQt>
24 #include <osgQt/QFontImplementation>
25 
26 #include <osgDB/ReadFile>
27 #include <osgDB/WriteFile>
28 #include <osgDB/Registry>
29 
30 #include <osgGA/StateSetManipulator>
31 #include <osgGA/TrackballManipulator>
32 #include <osgViewer/CompositeViewer>
33 #include <osgViewer/ViewerEventHandlers>
34 
35 #include <osg/Geode>
36 #include <osg/Camera>
37 #include <osg/ShapeDrawable>
38 #include <osg/Sequence>
39 #include <osg/PolygonMode>
40 
41 #include <osgText/Font>
42 #include <osgText/Text>
43 
createHUDText()44 osg::Group* createHUDText()
45 {
46 
47     osg::Group* rootNode = new osg::Group;
48 
49     osgText::Font* font = new osgText::Font(new osgQt::QFontImplementation(QFont("Arial")));
50 
51     osg::Geode* geode  = new osg::Geode;
52     rootNode->addChild(geode);
53 
54     float windowHeight = 1024.0f;
55     float windowWidth = 1280.0f;
56     float margin = 50.0f;
57 
58 
59 ////////////////////////////////////////////////////////////////////////////////////////////////////////
60 //
61 // Examples of how to set up different text layout
62 //
63 
64     osg::Vec4 layoutColor(1.0f,1.0f,0.0f,1.0f);
65     float layoutCharacterSize = 20.0f;
66 
67     {
68         osgText::Text* text = new osgText::Text;
69         text->setFont(font);
70         text->setColor(layoutColor);
71         text->setCharacterSize(layoutCharacterSize);
72         text->setPosition(osg::Vec3(margin,windowHeight-margin,0.0f));
73 
74         // the default layout is left to right, typically used in languages
75         // originating from europe such as English, French, German, Spanish etc..
76         text->setLayout(osgText::Text::LEFT_TO_RIGHT);
77 
78         text->setText("text->setLayout(osgText::Text::LEFT_TO_RIGHT);");
79         geode->addDrawable(text);
80     }
81 
82     {
83         osgText::Text* text = new osgText::Text;
84         text->setFont(font);
85         text->setColor(layoutColor);
86         text->setCharacterSize(layoutCharacterSize);
87         text->setPosition(osg::Vec3(windowWidth-margin,windowHeight-margin,0.0f));
88 
89         // right to left layouts would be used for hebrew or arabic fonts.
90         text->setLayout(osgText::Text::RIGHT_TO_LEFT);
91         text->setAlignment(osgText::Text::RIGHT_BASE_LINE);
92 
93         text->setText("text->setLayout(osgText::Text::RIGHT_TO_LEFT);");
94         geode->addDrawable(text);
95     }
96 
97     {
98         osgText::Text* text = new osgText::Text;
99         text->setFont(font);
100         text->setColor(layoutColor);
101         text->setPosition(osg::Vec3(margin,windowHeight-margin,0.0f));
102         text->setCharacterSize(layoutCharacterSize);
103 
104         // vertical font layout would be used for asian fonts.
105         text->setLayout(osgText::Text::VERTICAL);
106 
107         text->setText("text->setLayout(osgText::Text::VERTICAL);");
108         geode->addDrawable(text);
109     }
110 
111 
112 ////////////////////////////////////////////////////////////////////////////////////////////////////////
113 //
114 // Examples of how to set up different font resolution
115 //
116 
117     osg::Vec4 fontSizeColor(0.0f,1.0f,1.0f,1.0f);
118     float fontSizeCharacterSize = 30;
119 
120     osg::Vec3 cursor = osg::Vec3(margin*2,windowHeight-margin*2,0.0f);
121 
122     {
123         osgText::Text* text = new osgText::Text;
124         text->setFont(font);
125         text->setColor(fontSizeColor);
126         text->setCharacterSize(fontSizeCharacterSize);
127         text->setPosition(cursor);
128 
129         // use text that uses 10 by 10 texels as a target resolution for fonts.
130         text->setFontResolution(10,10); // blocky but small texture memory usage
131 
132         text->setText("text->setFontResolution(10,10); // blocky but small texture memory usage");
133         geode->addDrawable(text);
134     }
135 
136     cursor.y() -= fontSizeCharacterSize;
137     {
138         osgText::Text* text = new osgText::Text;
139         text->setFont(font);
140         text->setColor(fontSizeColor);
141         text->setCharacterSize(fontSizeCharacterSize);
142         text->setPosition(cursor);
143 
144         // use text that uses 20 by 20 texels as a target resolution for fonts.
145         text->setFontResolution(20,20); // smoother but higher texture memory usage (but still quite low).
146 
147         text->setText("text->setFontResolution(20,20); // smoother but higher texture memory usage (but still quite low).");
148         geode->addDrawable(text);
149     }
150 
151     cursor.y() -= fontSizeCharacterSize;
152     {
153         osgText::Text* text = new osgText::Text;
154         text->setFont(font);
155         text->setColor(fontSizeColor);
156         text->setCharacterSize(fontSizeCharacterSize);
157         text->setPosition(cursor);
158 
159         // use text that uses 40 by 40 texels as a target resolution for fonts.
160         text->setFontResolution(40,40); // even smoother but again higher texture memory usage.
161 
162         text->setText("text->setFontResolution(40,40); // even smoother but again higher texture memory usage.");
163         geode->addDrawable(text);
164     }
165 
166 
167 ////////////////////////////////////////////////////////////////////////////////////////////////////////
168 //
169 // Examples of how to set up different sized text
170 //
171 
172     osg::Vec4 characterSizeColor(1.0f,0.0f,1.0f,1.0f);
173 
174     cursor.y() -= fontSizeCharacterSize*2.0f;
175 
176     {
177         osgText::Text* text = new osgText::Text;
178         text->setFont(font);
179         text->setColor(characterSizeColor);
180         text->setFontResolution(20,20);
181         text->setPosition(cursor);
182 
183         // use text that is 20 units high.
184         text->setCharacterSize(20); // small
185 
186         text->setText("text->setCharacterSize(20.0f); // small");
187         geode->addDrawable(text);
188     }
189 
190     cursor.y() -= 30.0f;
191     {
192         osgText::Text* text = new osgText::Text;
193         text->setFont(font);
194         text->setColor(characterSizeColor);
195         text->setFontResolution(30,30);
196         text->setPosition(cursor);
197 
198         // use text that is 30 units high.
199         text->setCharacterSize(30.0f); // medium
200 
201         text->setText("text->setCharacterSize(30.0f); // medium");
202         geode->addDrawable(text);
203     }
204 
205     cursor.y() -= 50.0f;
206     {
207         osgText::Text* text = new osgText::Text;
208         text->setFont(font);
209         text->setColor(characterSizeColor);
210         text->setFontResolution(40,40);
211         text->setPosition(cursor);
212 
213         // use text that is 60 units high.
214         text->setCharacterSize(60.0f); // large
215 
216         text->setText("text->setCharacterSize(60.0f); // large");
217         geode->addDrawable(text);
218     }
219 
220 
221 ////////////////////////////////////////////////////////////////////////////////////////////////////////
222 //
223 // Examples of how to set up different alignments
224 //
225 
226     osg::Vec4 alignmentSizeColor(0.0f,1.0f,0.0f,1.0f);
227     float alignmentCharacterSize = 25.0f;
228     cursor.x() = 640;
229     cursor.y() = margin*4.0f;
230 
231     typedef std::pair<osgText::Text::AlignmentType,std::string> AlignmentPair;
232     typedef std::vector<AlignmentPair> AlignmentList;
233     AlignmentList alignmentList;
234     alignmentList.push_back(AlignmentPair(osgText::Text::LEFT_TOP,"text->setAlignment(\nosgText::Text::LEFT_TOP);"));
235     alignmentList.push_back(AlignmentPair(osgText::Text::LEFT_CENTER,"text->setAlignment(\nosgText::Text::LEFT_CENTER);"));
236     alignmentList.push_back(AlignmentPair(osgText::Text::LEFT_BOTTOM,"text->setAlignment(\nosgText::Text::LEFT_BOTTOM);"));
237     alignmentList.push_back(AlignmentPair(osgText::Text::CENTER_TOP,"text->setAlignment(\nosgText::Text::CENTER_TOP);"));
238     alignmentList.push_back(AlignmentPair(osgText::Text::CENTER_CENTER,"text->setAlignment(\nosgText::Text::CENTER_CENTER);"));
239     alignmentList.push_back(AlignmentPair(osgText::Text::CENTER_BOTTOM,"text->setAlignment(\nosgText::Text::CENTER_BOTTOM);"));
240     alignmentList.push_back(AlignmentPair(osgText::Text::RIGHT_TOP,"text->setAlignment(\nosgText::Text::RIGHT_TOP);"));
241     alignmentList.push_back(AlignmentPair(osgText::Text::RIGHT_CENTER,"text->setAlignment(\nosgText::Text::RIGHT_CENTER);"));
242     alignmentList.push_back(AlignmentPair(osgText::Text::RIGHT_BOTTOM,"text->setAlignment(\nosgText::Text::RIGHT_BOTTOM);"));
243     alignmentList.push_back(AlignmentPair(osgText::Text::LEFT_BASE_LINE,"text->setAlignment(\nosgText::Text::LEFT_BASE_LINE);"));
244     alignmentList.push_back(AlignmentPair(osgText::Text::CENTER_BASE_LINE,"text->setAlignment(\nosgText::Text::CENTER_BASE_LINE);"));
245     alignmentList.push_back(AlignmentPair(osgText::Text::RIGHT_BASE_LINE,"text->setAlignment(\nosgText::Text::RIGHT_BASE_LINE);"));
246     alignmentList.push_back(AlignmentPair(osgText::Text::LEFT_BOTTOM_BASE_LINE,"text->setAlignment(\nosgText::Text::LEFT_BOTTOM_BASE_LINE);"));
247     alignmentList.push_back(AlignmentPair(osgText::Text::CENTER_BOTTOM_BASE_LINE,"text->setAlignment(\nosgText::Text::CENTER_BOTTOM_BASE_LINE);"));
248     alignmentList.push_back(AlignmentPair(osgText::Text::RIGHT_BOTTOM_BASE_LINE,"text->setAlignment(\nosgText::Text::RIGHT_BOTTOM_BASE_LINE);"));
249 
250 
251     osg::Sequence* sequence = new osg::Sequence;
252     {
253         for(AlignmentList::iterator itr=alignmentList.begin();
254             itr!=alignmentList.end();
255             ++itr)
256         {
257             osg::Geode* alignmentGeode = new osg::Geode;
258             sequence->addChild(alignmentGeode);
259             sequence->setTime(sequence->getNumChildren(), 1.0f);
260 
261             osgText::Text* text = new osgText::Text;
262             text->setFont(font);
263             text->setColor(alignmentSizeColor);
264             text->setCharacterSize(alignmentCharacterSize);
265             text->setPosition(cursor);
266             text->setDrawMode(osgText::Text::TEXT|osgText::Text::ALIGNMENT|osgText::Text::BOUNDINGBOX);
267 
268             text->setAlignment(itr->first);
269             text->setText(itr->second);
270 
271             alignmentGeode->addDrawable(text);
272 
273 
274         }
275 
276     }
277 
278     sequence->setMode(osg::Sequence::START);
279     sequence->setInterval(osg::Sequence::LOOP, 0, -1);
280     sequence->setDuration(1.0f, -1);
281 
282     rootNode->addChild(sequence);
283 
284 
285 ////////////////////////////////////////////////////////////////////////////////////////////////////////
286 //
287 // Examples of how to set up different fonts...
288 //
289 
290     cursor.x() = margin*2.0f;
291     cursor.y() = margin*2.0f;
292 
293     osg::Vec4 fontColor(1.0f,0.5f,0.0f,1.0f);
294     float fontCharacterSize = 20.0f;
295     float spacing = 40.0f;
296 
297     {
298         osgText::Text* text = new osgText::Text;
299         text->setColor(fontColor);
300         text->setPosition(cursor);
301         text->setCharacterSize(fontCharacterSize);
302 
303         text->setFont(0);
304         text->setText("text->setFont(0); // inbuilt font.");
305         geode->addDrawable(text);
306 
307         cursor.x() = text->getBoundingBox().xMax() + spacing ;
308     }
309 
310     {
311         osgText::Font* arial = new osgText::Font(new osgQt::QFontImplementation(QFont("Arial")));
312 
313         osgText::Text* text = new osgText::Text;
314         text->setColor(fontColor);
315         text->setPosition(cursor);
316         text->setCharacterSize(fontCharacterSize);
317 
318         text->setFont(arial);
319         text->setText(arial!=0?
320                       "text->setFont(\"fonts/arial.ttf\");":
321                       "unable to load \"fonts/arial.ttf\"");
322         geode->addDrawable(text);
323 
324         cursor.x() = text->getBoundingBox().xMax() + spacing ;
325     }
326 
327     {
328         osgText::Font* times = new osgText::Font(new osgQt::QFontImplementation(QFont("Times")));
329 
330         osgText::Text* text = new osgText::Text;
331         text->setColor(fontColor);
332         text->setPosition(cursor);
333         text->setCharacterSize(fontCharacterSize);
334 
335         geode->addDrawable(text);
336         text->setFont(times);
337         text->setText(times!=0?
338                       "text->setFont(\"fonts/times.ttf\");":
339                       "unable to load \"fonts/times.ttf\"");
340 
341         cursor.x() = text->getBoundingBox().xMax() + spacing ;
342     }
343 
344     cursor.x() = margin*2.0f;
345     cursor.y() = margin;
346 
347     {
348         osgText::Font* dirtydoz = new osgText::Font(new osgQt::QFontImplementation(QFont("Times")));
349 
350         osgText::Text* text = new osgText::Text;
351         text->setColor(fontColor);
352         text->setPosition(cursor);
353         text->setCharacterSize(fontCharacterSize);
354 
355         text->setFont(dirtydoz);
356         text->setText(dirtydoz!=0?
357                       "text->setFont(\"fonts/dirtydoz.ttf\");":
358                       "unable to load \"fonts/dirtydoz.ttf\"");
359         geode->addDrawable(text);
360 
361         cursor.x() = text->getBoundingBox().xMax() + spacing ;
362     }
363 
364     {
365         osgText::Font* fudd = new osgText::Font(new osgQt::QFontImplementation(QFont("Times")));
366 
367         osgText::Text* text = new osgText::Text;
368         text->setColor(fontColor);
369         text->setPosition(cursor);
370         text->setCharacterSize(fontCharacterSize);
371 
372         text->setFont(fudd);
373         text->setText(fudd!=0?
374                       "text->setFont(\"fonts/fudd.ttf\");":
375                       "unable to load \"fonts/fudd.ttf\"");
376         geode->addDrawable(text);
377 
378         cursor.x() = text->getBoundingBox().xMax() + spacing ;
379     }
380 
381     return rootNode;
382 }
383 
384 
385 
386 
387 // create text which sits in 3D space such as would be inserted into a normal model
create3DText(const osg::Vec3 & center,float radius)388 osg::Group* create3DText(const osg::Vec3& center,float radius)
389 {
390 
391     osg::Geode* geode  = new osg::Geode;
392 
393 ////////////////////////////////////////////////////////////////////////////////////////////////////////
394 //
395 // Examples of how to set up axis/orientation alignments
396 //
397 
398     float characterSize=radius*0.2f;
399 
400     osg::Vec3 pos(center.x()-radius*.5f,center.y()-radius*.5f,center.z()-radius*.5f);
401 
402     osgText::Text* text1 = new osgText::Text;
403     text1->setFont(new osgText::Font(new osgQt::QFontImplementation(QFont("Times"))));
404     text1->setCharacterSize(characterSize);
405     text1->setPosition(pos);
406     text1->setAxisAlignment(osgText::Text::XY_PLANE);
407     text1->setText("XY_PLANE");
408     geode->addDrawable(text1);
409 
410     osgText::Text* text2 = new osgText::Text;
411     text2->setFont(new osgText::Font(new osgQt::QFontImplementation(QFont("Times"))));
412     text2->setCharacterSize(characterSize);
413     text2->setPosition(pos);
414     text2->setAxisAlignment(osgText::Text::YZ_PLANE);
415     text2->setText("YZ_PLANE");
416     geode->addDrawable(text2);
417 
418     osgText::Text* text3 = new osgText::Text;
419     text3->setFont(new osgText::Font(new osgQt::QFontImplementation(QFont("Times"))));
420     text3->setCharacterSize(characterSize);
421     text3->setPosition(pos);
422     text3->setAxisAlignment(osgText::Text::XZ_PLANE);
423     text3->setText("XZ_PLANE");
424     geode->addDrawable(text3);
425 
426 
427     osgText::Text* text4 = new osgText::Text;
428     text4->setFont(new osgText::Font(new osgQt::QFontImplementation(QFont("Times"))));
429     text4->setCharacterSize(characterSize);
430     text4->setPosition(center);
431     text4->setAxisAlignment(osgText::Text::SCREEN);
432 
433     osg::Vec4 characterSizeModeColor(1.0f,0.0f,0.5f,1.0f);
434 
435     osgText::Text* text5 = new osgText::Text;
436     text5->setColor(characterSizeModeColor);
437     text5->setFont(new osgText::Font(new osgQt::QFontImplementation(QFont("Times"))));
438     //text5->setCharacterSize(characterSize);
439     text5->setCharacterSize(32.0f); // medium
440     text5->setPosition(center - osg::Vec3(0.0, 0.0, 0.2));
441     text5->setAxisAlignment(osgText::Text::SCREEN);
442     text5->setCharacterSizeMode(osgText::Text::SCREEN_COORDS);
443     text5->setText("CharacterSizeMode SCREEN_COORDS(size 32.0)");
444     geode->addDrawable(text5);
445 
446     osgText::Text* text6 = new osgText::Text;
447     text6->setColor(characterSizeModeColor);
448     text6->setFont(new osgText::Font(new osgQt::QFontImplementation(QFont("Times"))));
449     text6->setCharacterSize(characterSize);
450     text6->setPosition(center - osg::Vec3(0.0, 0.0, 0.4));
451     text6->setAxisAlignment(osgText::Text::SCREEN);
452     text6->setCharacterSizeMode(osgText::Text::OBJECT_COORDS_WITH_MAXIMUM_SCREEN_SIZE_CAPPED_BY_FONT_HEIGHT);
453     text6->setText("CharacterSizeMode OBJECT_COORDS_WITH_MAXIMUM_SCREEN_SIZE_CAPPED_BY_FONT_HEIGHT");
454     geode->addDrawable(text6);
455 
456     osgText::Text* text7 = new osgText::Text;
457     text7->setColor(characterSizeModeColor);
458     text7->setFont(new osgText::Font(new osgQt::QFontImplementation(QFont("Times"))));
459     text7->setCharacterSize(characterSize);
460     text7->setPosition(center - osg::Vec3(0.0, 0.0, 0.6));
461     text7->setAxisAlignment(osgText::Text::SCREEN);
462     text7->setCharacterSizeMode(osgText::Text::OBJECT_COORDS);
463     text7->setText("CharacterSizeMode OBJECT_COORDS (default)");
464     geode->addDrawable(text7);
465 
466 #if 1
467     // reproduce outline bounding box compute problem with backdrop on.
468     text4->setBackdropType(osgText::Text::OUTLINE);
469     text4->setDrawMode(osgText::Text::TEXT | osgText::Text::BOUNDINGBOX);
470 #endif
471 
472     text4->setText("SCREEN");
473     geode->addDrawable(text4);
474 
475     osg::ShapeDrawable* shape = new osg::ShapeDrawable(new osg::Sphere(center,characterSize*0.2f));
476     shape->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::ON);
477     geode->addDrawable(shape);
478 
479     osg::Group* rootNode = new osg::Group;
480     rootNode->addChild(geode);
481 
482     return rootNode;
483 }
484 
485 class MainWindow : public QWidget {
486 public:
MainWindow()487     MainWindow()
488     {
489         osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits(osg::DisplaySettings::instance().get());
490         traits->width = width();
491         traits->height = height();
492         traits->doubleBuffer = true;
493         osgQt::GraphicsWindowQt* graphicsWindow = new osgQt::GraphicsWindowQt(traits.get());
494 
495         QGridLayout* grid = new QGridLayout;
496         grid->setMargin(0);
497         grid->addWidget(graphicsWindow->getGLWidget(), 0, 0);
498         setLayout(grid);
499 
500         _viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded);
501 
502         osg::Camera* camera = _viewer.getCamera();
503         camera->setGraphicsContext(graphicsWindow);
504         camera->setViewport(new osg::Viewport(0, 0, width(), height()));
505 
506         startTimer(10);
507     }
508 
paintEvent(QPaintEvent * event)509     virtual void paintEvent(QPaintEvent* event)
510     {
511         _viewer.frame();
512     }
timerEvent(QTimerEvent * event)513     virtual void timerEvent(QTimerEvent* event)
514     {
515         _viewer.frame();
516     }
517 
setSceneData(osg::Node * node)518     void setSceneData(osg::Node* node)
519     {
520         _viewer.setSceneData(node);
521     }
setCameraManipulator(osgGA::CameraManipulator * manipulator,bool resetPosition=true)522     void setCameraManipulator(osgGA::CameraManipulator* manipulator, bool resetPosition = true)
523     {
524         _viewer.setCameraManipulator(manipulator, resetPosition);
525     }
526 
527 private:
528     osgViewer::Viewer _viewer;
529 };
530 
main(int argc,char ** argv)531 int main(int argc, char** argv)
532 {
533     QApplication app(argc, argv);
534 
535     // prepare scene.
536     osg::Vec3 center(0.0f,0.0f,0.0f);
537     float radius = 1.0f;
538 
539     // create the hud.
540     osg::ref_ptr<osg::Camera> camera = new osg::Camera;
541     camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
542     camera->setProjectionMatrixAsOrtho2D(0,1280,0,1024);
543     camera->setViewMatrix(osg::Matrix::identity());
544     camera->setClearMask(GL_DEPTH_BUFFER_BIT);
545     camera->addChild(createHUDText());
546     camera->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
547 
548     // make sure the root node is group so we can add extra nodes to it.
549     osg::ref_ptr<osg::Group> group = new osg::Group;
550     group->addChild(camera.get());
551     group->addChild(create3DText(center, radius));
552 
553     // The qt window
554     MainWindow widget;
555 
556     // set the scene to render
557     widget.setSceneData(group.get());
558     widget.setCameraManipulator(new osgGA::TrackballManipulator);
559 
560     widget.setGeometry(100, 100, 800, 600);
561     widget.show();
562 
563     return app.exec();
564 }
565