OpenSceneGraph 3.0: Beginner's Guide
上QQ阅读APP看书,第一时间看更新

Time for action—saving the log file

We will make use of the std::ofstream class to redirect the OSG internal notify messages to an external log file. The virtual function notify() of the osg::NotifyHandler derived class should be overridden to apply standard file stream operations, and a global function osg::setNotifyHandler() is called before everything starts as well.

  1. Include the necessary headers:
    #include <osgDB/ReadFile>
    #include <osgViewer/Viewer>
    #include <fstream>
  2. Implement the derived class LogFileHandler, which will redirect notify messages to the file stream:
    class LogFileHandler : public osg::NotifyHandler
    {
    public:
        LogFileHandler( const std::string& file )
        { _log.open( file.c_str() ); }
        virtual ~LogFileHandler() { _log.close(); }
        
        virtual void notify(osg::NotifySeverity severity, const char* msg)
        { _log << msg; }
        
    protected:
        std::ofstream _log;
    };
  3. Now set a new notify handler to the entire OSG system, and work under the INFO level to see more verbose messages. The function osgDB::readNodeFiles here directly reads all usable filenames from the command line and merges them into the root node. We also add an OSG_FATAL macro to check if there is no scene graph data loaded:
    int main( int argc, char** argv )
    {
        osg::setNotifyLevel( osg::INFO );
        osg::setNotifyHandler( new LogFileHandler("output.txt") );
        
        osg::ArgumentParser arguments( &argc, argv );
        osg::ref_ptr<osg::Node> root = osgDB::readNodeFiles( arguments );
        if ( !root )
        {
            OSG_FATAL << arguments.getApplicationName()
                      <<": No data loaded." << std::endl;
            return -1;
        }
        
        osgViewer::Viewer viewer;
        viewer.setSceneData( root.get() );
        return viewer.run();
    }
  4. Build and start the example. All information will be saved in the log file output.txt, which is also indicated in the example. Try the command line with the newly-generated executable MyProject.exe this time:
    # MyProject.exe dumptruck.osg
  5. Press the Esc key to quit, and then open the resulting log file in the working directory with notepad (on Windows) or any text editor:
    Time for action—saving the log file
  6. Don't be discouraged if you can't read and understand all of the information listed here. It only shows how OSG is starting and getting every part to work properly. It will be of great help in future development.

What just happened?

By default, OSG will send messages to the standard output stream std::cout and error stream std::cerr. However, these messages can be easily redirected to other streams and even the GUI text windows. A log file here is friendly to end users and helps them a lot, while sending feedbacks.

Besides, setting the osg::setNotifyLevel() function will make the notify level reset to the specified level or a higher level. The notifier system then ignores statements from lower levels and prints nothing to the output stream. For instance, assuming that you have the following lines in your application:

osg::setNotifyLevel( osg::FATAL );
…
osg::notify(osg::WARN) << "Some warn message." << std::endl;

The message with the notifier level lower than FATAL will not be printed any more.

The environment variable OSG_NOTIFY_LEVEL, which was mentioned in the previous chapter, can be used to control the displayed message level, too, for any OSG-based applications.