/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include osg::Group* createHUDText() { osg::Group* rootNode = new osg::Group; osgText::Font* font = osgText::readFontFile("fonts/arial.ttf"); osg::Geode* geode = new osg::Geode; rootNode->addChild(geode); float windowHeight = 1024.0f; float windowWidth = 1280.0f; float margin = 50.0f; //////////////////////////////////////////////////////////////////////////////////////////////////////// // // Examples of how to set up different text layout // osg::Vec4 layoutColor(1.0f,1.0f,0.0f,1.0f); float layoutCharacterSize = 20.0f; { osgText::Text* text = new osgText::Text; text->setFont(font); text->setColor(layoutColor); text->setCharacterSize(layoutCharacterSize); text->setPosition(osg::Vec3(margin,windowHeight-margin,0.0f)); // the default layout is left to right, typically used in languages // originating from europe such as English, French, German, Spanish etc.. text->setLayout(osgText::Text::LEFT_TO_RIGHT); text->setText("text->setLayout(osgText::Text::LEFT_TO_RIGHT);"); geode->addDrawable(text); } { osgText::Text* text = new osgText::Text; text->setFont(font); text->setColor(layoutColor); text->setCharacterSize(layoutCharacterSize); text->setPosition(osg::Vec3(windowWidth-margin,windowHeight-margin,0.0f)); // right to left layouts would be used for hebrew or arabic fonts. text->setLayout(osgText::Text::RIGHT_TO_LEFT); text->setAlignment(osgText::Text::RIGHT_BASE_LINE); text->setText("text->setLayout(osgText::Text::RIGHT_TO_LEFT);"); geode->addDrawable(text); } { osgText::Text* text = new osgText::Text; text->setFont(font); text->setColor(layoutColor); text->setPosition(osg::Vec3(margin,windowHeight-margin,0.0f)); text->setCharacterSize(layoutCharacterSize); // vertical font layout would be used for asian fonts. text->setLayout(osgText::Text::VERTICAL); text->setText("text->setLayout(osgText::Text::VERTICAL);"); geode->addDrawable(text); } //////////////////////////////////////////////////////////////////////////////////////////////////////// // // Examples of how to set up different font resolution // osg::Vec4 fontSizeColor(0.0f,1.0f,1.0f,1.0f); float fontSizeCharacterSize = 30; osg::Vec3 cursor = osg::Vec3(margin*2,windowHeight-margin*2,0.0f); { osgText::Text* text = new osgText::Text; text->setFont(font); text->setColor(fontSizeColor); text->setCharacterSize(fontSizeCharacterSize); text->setPosition(cursor); // use text that uses 10 by 10 texels as a target resolution for fonts. text->setFontResolution(10,10); // blocky but small texture memory usage text->setText("text->setFontResolution(10,10); // blocky but small texture memory usage"); geode->addDrawable(text); } cursor.y() -= fontSizeCharacterSize; { osgText::Text* text = new osgText::Text; text->setFont(font); text->setColor(fontSizeColor); text->setCharacterSize(fontSizeCharacterSize); text->setPosition(cursor); // use text that uses 20 by 20 texels as a target resolution for fonts. text->setFontResolution(20,20); // smoother but higher texture memory usage (but still quite low). text->setText("text->setFontResolution(20,20); // smoother but higher texture memory usage (but still quite low)."); geode->addDrawable(text); } cursor.y() -= fontSizeCharacterSize; { osgText::Text* text = new osgText::Text; text->setFont(font); text->setColor(fontSizeColor); text->setCharacterSize(fontSizeCharacterSize); text->setPosition(cursor); // use text that uses 40 by 40 texels as a target resolution for fonts. text->setFontResolution(40,40); // even smoother but again higher texture memory usage. text->setText("text->setFontResolution(40,40); // even smoother but again higher texture memory usage."); geode->addDrawable(text); } //////////////////////////////////////////////////////////////////////////////////////////////////////// // // Examples of how to set up different sized text // osg::Vec4 characterSizeColor(1.0f,0.0f,1.0f,1.0f); cursor.y() -= fontSizeCharacterSize*2.0f; { osgText::Text* text = new osgText::Text; text->setFont(font); text->setColor(characterSizeColor); text->setFontResolution(20,20); text->setPosition(cursor); // use text that is 20 units high. text->setCharacterSize(20); // small text->setText("text->setCharacterSize(20.0f); // small"); geode->addDrawable(text); } cursor.y() -= 30.0f; { osgText::Text* text = new osgText::Text; text->setFont(font); text->setColor(characterSizeColor); text->setFontResolution(30,30); text->setPosition(cursor); // use text that is 30 units high. text->setCharacterSize(30.0f); // medium text->setText("text->setCharacterSize(30.0f); // medium"); geode->addDrawable(text); } cursor.y() -= 50.0f; { osgText::Text* text = new osgText::Text; text->setFont(font); text->setColor(characterSizeColor); text->setFontResolution(40,40); text->setPosition(cursor); // use text that is 60 units high. text->setCharacterSize(60.0f); // large text->setText("text->setCharacterSize(60.0f); // large"); geode->addDrawable(text); } //////////////////////////////////////////////////////////////////////////////////////////////////////// // // Examples of how to set up different alignments // osg::Vec4 alignmentSizeColor(0.0f,1.0f,0.0f,1.0f); float alignmentCharacterSize = 25.0f; cursor.x() = 640; cursor.y() = margin*4.0f; typedef std::pair AlignmentPair; typedef std::vector AlignmentList; AlignmentList alignmentList; alignmentList.push_back(AlignmentPair(osgText::Text::LEFT_TOP,"text->setAlignment(\nosgText::Text::LEFT_TOP);")); alignmentList.push_back(AlignmentPair(osgText::Text::LEFT_CENTER,"text->setAlignment(\nosgText::Text::LEFT_CENTER);")); alignmentList.push_back(AlignmentPair(osgText::Text::LEFT_BOTTOM,"text->setAlignment(\nosgText::Text::LEFT_BOTTOM);")); alignmentList.push_back(AlignmentPair(osgText::Text::CENTER_TOP,"text->setAlignment(\nosgText::Text::CENTER_TOP);")); alignmentList.push_back(AlignmentPair(osgText::Text::CENTER_CENTER,"text->setAlignment(\nosgText::Text::CENTER_CENTER);")); alignmentList.push_back(AlignmentPair(osgText::Text::CENTER_BOTTOM,"text->setAlignment(\nosgText::Text::CENTER_BOTTOM);")); alignmentList.push_back(AlignmentPair(osgText::Text::RIGHT_TOP,"text->setAlignment(\nosgText::Text::RIGHT_TOP);")); alignmentList.push_back(AlignmentPair(osgText::Text::RIGHT_CENTER,"text->setAlignment(\nosgText::Text::RIGHT_CENTER);")); alignmentList.push_back(AlignmentPair(osgText::Text::RIGHT_BOTTOM,"text->setAlignment(\nosgText::Text::RIGHT_BOTTOM);")); alignmentList.push_back(AlignmentPair(osgText::Text::LEFT_BASE_LINE,"text->setAlignment(\nosgText::Text::LEFT_BASE_LINE);")); alignmentList.push_back(AlignmentPair(osgText::Text::CENTER_BASE_LINE,"text->setAlignment(\nosgText::Text::CENTER_BASE_LINE);")); alignmentList.push_back(AlignmentPair(osgText::Text::RIGHT_BASE_LINE,"text->setAlignment(\nosgText::Text::RIGHT_BASE_LINE);")); alignmentList.push_back(AlignmentPair(osgText::Text::LEFT_BOTTOM_BASE_LINE,"text->setAlignment(\nosgText::Text::LEFT_BOTTOM_BASE_LINE);")); alignmentList.push_back(AlignmentPair(osgText::Text::CENTER_BOTTOM_BASE_LINE,"text->setAlignment(\nosgText::Text::CENTER_BOTTOM_BASE_LINE);")); alignmentList.push_back(AlignmentPair(osgText::Text::RIGHT_BOTTOM_BASE_LINE,"text->setAlignment(\nosgText::Text::RIGHT_BOTTOM_BASE_LINE);")); osg::Sequence* sequence = new osg::Sequence; { for(AlignmentList::iterator itr=alignmentList.begin(); itr!=alignmentList.end(); ++itr) { osg::Geode* alignmentGeode = new osg::Geode; sequence->addChild(alignmentGeode); sequence->setTime(sequence->getNumChildren(), 1.0f); osgText::Text* text = new osgText::Text; text->setFont(font); text->setColor(alignmentSizeColor); text->setCharacterSize(alignmentCharacterSize); text->setPosition(cursor); text->setDrawMode(osgText::Text::TEXT|osgText::Text::ALIGNMENT|osgText::Text::BOUNDINGBOX); text->setAlignment(itr->first); text->setText(itr->second); alignmentGeode->addDrawable(text); } } sequence->setMode(osg::Sequence::START); sequence->setInterval(osg::Sequence::LOOP, 0, -1); sequence->setDuration(1.0f, -1); rootNode->addChild(sequence); //////////////////////////////////////////////////////////////////////////////////////////////////////// // // Examples of how to set up different fonts... // cursor.x() = margin*2.0f; cursor.y() = margin*2.0f; osg::Vec4 fontColor(1.0f,0.5f,0.0f,1.0f); float fontCharacterSize = 20.0f; float spacing = 40.0f; { osgText::Text* text = new osgText::Text; text->setColor(fontColor); text->setPosition(cursor); text->setCharacterSize(fontCharacterSize); text->setFont(0); text->setText("text->setFont(0); // inbuilt font."); geode->addDrawable(text); cursor.x() = text->getBound().xMax() + spacing ; } { osgText::Font* arial = osgText::readFontFile("fonts/arial.ttf"); osgText::Text* text = new osgText::Text; text->setColor(fontColor); text->setPosition(cursor); text->setCharacterSize(fontCharacterSize); text->setFont(arial); text->setText(arial!=0? "text->setFont(\"fonts/arial.ttf\");": "unable to load \"fonts/arial.ttf\""); geode->addDrawable(text); cursor.x() = text->getBound().xMax() + spacing ; } { osgText::Font* times = osgText::readFontFile("fonts/times.ttf"); osgText::Text* text = new osgText::Text; text->setColor(fontColor); text->setPosition(cursor); text->setCharacterSize(fontCharacterSize); geode->addDrawable(text); text->setFont(times); text->setText(times!=0? "text->setFont(\"fonts/times.ttf\");": "unable to load \"fonts/times.ttf\""); cursor.x() = text->getBound().xMax() + spacing ; } cursor.x() = margin*2.0f; cursor.y() = margin; { osgText::Font* dirtydoz = osgText::readFontFile("fonts/dirtydoz.ttf"); osgText::Text* text = new osgText::Text; text->setColor(fontColor); text->setPosition(cursor); text->setCharacterSize(fontCharacterSize); text->setFont(dirtydoz); text->setText(dirtydoz!=0? "text->setFont(\"fonts/dirtydoz.ttf\");": "unable to load \"fonts/dirtydoz.ttf\""); geode->addDrawable(text); cursor.x() = text->getBound().xMax() + spacing ; } { osgText::Font* fudd = osgText::readFontFile("fonts/fudd.ttf"); osgText::Text* text = new osgText::Text; text->setColor(fontColor); text->setPosition(cursor); text->setCharacterSize(fontCharacterSize); text->setFont(fudd); text->setText(fudd!=0? "text->setFont(\"fonts/fudd.ttf\");": "unable to load \"fonts/fudd.ttf\""); geode->addDrawable(text); cursor.x() = text->getBound().xMax() + spacing ; } return rootNode; } // create text which sits in 3D space such as would be inserted into a normal model osg::Group* create3DText(const osg::Vec3& center,float radius) { osg::Geode* geode = new osg::Geode; //////////////////////////////////////////////////////////////////////////////////////////////////////// // // Examples of how to set up axis/orientation alignments // float characterSize=radius*0.2f; osg::Vec3 pos(center.x()-radius*.5f,center.y()-radius*.5f,center.z()-radius*.5f); osgText::Text* text1 = new osgText::Text; text1->setFont("fonts/times.ttf"); text1->setCharacterSize(characterSize); text1->setPosition(pos); text1->setAxisAlignment(osgText::Text::XY_PLANE); text1->setText("XY_PLANE"); geode->addDrawable(text1); osgText::Text* text2 = new osgText::Text; text2->setFont("fonts/times.ttf"); text2->setCharacterSize(characterSize); text2->setPosition(pos); text2->setAxisAlignment(osgText::Text::YZ_PLANE); text2->setText("YZ_PLANE"); geode->addDrawable(text2); osgText::Text* text3 = new osgText::Text; text3->setFont("fonts/times.ttf"); text3->setCharacterSize(characterSize); text3->setPosition(pos); text3->setAxisAlignment(osgText::Text::XZ_PLANE); text3->setText("XZ_PLANE"); geode->addDrawable(text3); osgText::Text* text4 = new osgText::Text; text4->setFont("fonts/times.ttf"); text4->setCharacterSize(characterSize); text4->setPosition(center); text4->setAxisAlignment(osgText::Text::SCREEN); text4->setText("SCREEN"); geode->addDrawable(text4); osg::ShapeDrawable* shape = new osg::ShapeDrawable(new osg::Sphere(center,characterSize*0.2f)); shape->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::ON); geode->addDrawable(shape); osg::Group* rootNode = new osg::Group; rootNode->addChild(geode); return rootNode; } int main( int argc, char **argv ) { // use an ArgumentParser object to manage the program arguments. osg::ArgumentParser arguments(&argc,argv); // set up the usage document, in case we need to print out how to use this program. arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates use of text."); arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] [filename] ..."); arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information"); // construct the viewer. osgProducer::Viewer viewer(arguments); // set up the value with sensible default event handlers. viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS); // get details on keyboard and mouse bindings used by the viewer. viewer.getUsage(*arguments.getApplicationUsage()); // if user request help write it out to cout. if (arguments.read("-h") || arguments.read("--help")) { arguments.getApplicationUsage()->write(std::cout); return 1; } // any option left unread are converted into errors to write out later. arguments.reportRemainingOptionsAsUnrecognized(); // report any errors if they have occured when parsing the program aguments. if (arguments.errors()) { arguments.writeErrorMessages(std::cout); return 1; } // read the scene from the list of file specified commandline args. osg::ref_ptr rootNode = osgDB::readNodeFiles(arguments); // prepare scene. { osg::Vec3 center(0.0f,0.0f,0.0f); float radius = 1.0f; if (rootNode.valid()) { // optimize the scene graph, remove rendundent nodes and state etc. osgUtil::Optimizer optimizer; optimizer.optimize(rootNode.get()); const osg::BoundingSphere& bs = rootNode->getBound(); center = bs.center(); radius = bs.radius(); } // make sure the root node is group so we can add extra nodes to it. osg::Group* group = dynamic_cast(rootNode.get()); if (!group) { group = new osg::Group; if (rootNode.valid()) group->addChild(rootNode.get()); rootNode = group; } { // create the hud. osg::CameraNode* camera = new osg::CameraNode; camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); camera->setProjectionMatrixAsOrtho2D(0,1280,0,1024); camera->setViewMatrix(osg::Matrix::identity()); camera->setClearMask(GL_DEPTH_BUFFER_BIT); camera->addChild(createHUDText()); camera->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF); group->addChild(camera); } group->addChild(create3DText(center,radius)); } // set the scene to render viewer.setSceneData(rootNode.get()); // create the windows and run the threads. viewer.realize(); #if 0 // this optional compile block is done as a test against graphics // drivers that claim support for generate mip map, but the actual // implementation is flacky. It is not compiled by default. // go through each graphics context and switch off the generate mip map extension. // note, this must be done after the realize so that init of texture state and as // result extension structures have been iniatilized. for(unsigned int contextID = 0; contextIDgetMaxNumberOfGraphicsContexts(); ++contextID) { osg::Texture::Extensions* textureExt = osg::Texture::getExtensions(contextID,false); if (textureExt) textureExt->setGenerateMipMapSupported(false); } #endif while( !viewer.done() ) { // wait for all cull and draw threads to complete. viewer.sync(); // update the scene by traversing it with the the update visitor which will // call all node update callbacks and animations. viewer.update(); // fire off the cull and draw traversals of the scene. viewer.frame(); } // wait for all cull and draw threads to complete. viewer.sync(); // run a clean up frame to delete all OpenGL objects. viewer.cleanup_frame(); // wait for all the clean up frame to complete. viewer.sync(); return 0; }