root/OpenSceneGraph/trunk/examples/osgmultiplemovies/osgmultiplemovies.cpp @ 13376

Revision 13376, 23.8 kB (checked in by robert, 45 hours ago)

Fixed comment

Line 
1/* OpenSceneGraph example, osgmovie.
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 <osgViewer/Viewer>
20#include <osgViewer/ViewerEventHandlers>
21
22#include <osgDB/ReadFile>
23
24#include <osg/Geode>
25#include <osg/Geometry>
26#include <osg/StateSet>
27#include <osg/Material>
28#include <osg/Texture2D>
29#include <osg/TextureRectangle>
30#include <osg/TextureCubeMap>
31#include <osg/TexMat>
32#include <osg/CullFace>
33#include <osg/ImageStream>
34#include <osg/io_utils>
35
36#include <osgDB/FileUtils>
37
38#include <osgGA/TrackballManipulator>
39#include <osgGA/StateSetManipulator>
40#include <osgGA/EventVisitor>
41
42#include <iostream>
43
44class ImageStreamStateCallback : public osg::Drawable::UpdateCallback {
45public:
46    ImageStreamStateCallback(osgText::Text* text, osg::ImageStream* is)
47        : osg::Drawable::UpdateCallback()
48        , _text(text)
49        , _imageStream(is)
50        , _fps(0)
51        , _lastData(NULL)
52        , _lastDataTimeStamp(0)
53    {
54    }
55   
56    void setImageStream(osg::ImageStream* is) { _imageStream = is; }
57   
58    virtual void update(osg::NodeVisitor* nv, osg::Drawable*)
59    {
60        if (_text.valid() && _imageStream.valid())
61        {
62            if (_imageStream->data() != _lastData)
63            {
64                double dt = nv->getFrameStamp()->getReferenceTime() - _lastDataTimeStamp;
65               
66                _fps = 0.9 * _fps + 0.1 * (1 / dt);
67                _fps = osg::round(10 * _fps) / 10.0;
68               
69                _lastDataTimeStamp = nv->getFrameStamp()->getReferenceTime();
70                _lastData = _imageStream->data();
71            }
72           
73            std::ostringstream ss;
74            ss << _imageStream->s() << "x" << _imageStream->t() << " | " << _fps << "fps";
75            ss << " | len: " << osg::round(_imageStream->getLength()*10) / 10.0;
76            ss << " | cur: " << osg::round(_imageStream->getCurrentTime()*10) / 10.0;
77            if (_imageStream->getStatus() == osg::ImageStream::PLAYING)
78            {
79                ss << " | playing";
80            }
81            else
82            {
83                ss << " | paused";
84                _fps = 0;
85            }
86            if (_imageStream->getLoopingMode() == osg::ImageStream::LOOPING) {
87                ss << " | looping";
88            }
89            else
90            {
91                ss << " | don't loop";
92            }
93            _text->setText(ss.str());
94        }
95    }
96   
97   
98private:
99    osg::observer_ptr<osgText::Text> _text;
100    osg::observer_ptr<osg::ImageStream> _imageStream;
101    float _fps;
102    unsigned char* _lastData;
103    double _lastDataTimeStamp;
104   
105};
106
107class MovieEventHandler : public osgGA::GUIEventHandler
108{
109public:
110
111    MovieEventHandler()
112        : osgGA::GUIEventHandler()
113        , _currentImageStream()
114        , _currentGeometry()
115    {
116    }
117
118
119    virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa, osg::Object*, osg::NodeVisitor* nv);
120
121    virtual void getUsage(osg::ApplicationUsage& usage) const;
122
123protected:
124
125    void setColor(osg::Geometry* geo, const osg::Vec4& color)
126    {
127        if (!geo)
128            return;
129       
130        osg::Vec4Array* c = dynamic_cast<osg::Vec4Array*>(geo->getColorArray());
131        if (c) (*c)[0] = color;
132        geo->dirtyDisplayList();
133        c->dirty();
134    }
135
136    virtual ~MovieEventHandler() {}
137
138    osg::observer_ptr<osg::ImageStream> _currentImageStream;
139    osg::observer_ptr<osg::Geometry> _currentGeometry;
140
141};
142
143
144
145
146
147
148bool MovieEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa, osg::Object*, osg::NodeVisitor* nv)
149{
150    switch(ea.getEventType())
151    {
152        case(osgGA::GUIEventAdapter::MOVE):
153        {
154            if(_currentImageStream.valid() && (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_SHIFT))
155            {
156                float scalar = (ea.getXnormalized()+1) / 2.0;
157                _currentImageStream->seek(scalar * _currentImageStream->getLength());
158            }
159        }
160        break;
161           
162        case(osgGA::GUIEventAdapter::RELEASE):
163        {
164           
165            osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
166            osgUtil::LineSegmentIntersector::Intersections intersections;
167            bool foundIntersection = view==0 ? false : view->computeIntersections(ea, intersections);
168
169            if (foundIntersection)
170            {
171                // use the nearest intersection
172                const osgUtil::LineSegmentIntersector::Intersection& intersection = *(intersections.begin());
173                osg::Drawable* drawable = intersection.drawable.get();
174                osg::Geometry* geometry = drawable ? drawable->asGeometry() : 0;
175               
176                if (geometry) {
177                    osg::Texture* tex = geometry->getStateSet() ? dynamic_cast<osg::Texture*>(geometry->getStateSet()->getTextureAttribute(0, osg::StateAttribute::TEXTURE)) : NULL;
178                    if (tex) {
179                        osg::ImageStream* is = dynamic_cast<osg::ImageStream*>(tex->getImage(0));
180                        if (is)
181                        {
182                            setColor(_currentGeometry.get(), osg::Vec4(0.7, 0.7, 0.7, 1.0));
183                            _currentGeometry = geometry;
184                            setColor(_currentGeometry.get(), osg::Vec4(1,1,1,1));
185                            _currentImageStream = is;
186                           
187                            if (is->getStatus() == osg::ImageStream::PLAYING)
188                            {
189                                is->pause();
190                            }
191                            else
192                            {
193                                is->play();
194                            }
195                           
196                        }
197                    }
198                }
199            }
200   
201            break;
202        }
203        case(osgGA::GUIEventAdapter::KEYDOWN):
204        {
205            if (!_currentImageStream.valid())
206                return false;
207           
208            if (ea.getKey()=='p')
209            {
210                osg::ImageStream::StreamStatus playToggle = _currentImageStream->getStatus();
211                if (playToggle != osg::ImageStream::PLAYING)
212                {
213                    std::cout<< _currentImageStream.get() << " Play"<<std::endl;
214                    _currentImageStream->play();
215                }
216                else
217                {
218                    // playing, so pause
219                    std::cout<< _currentImageStream.get() << " Pause"<<std::endl;
220                    _currentImageStream->pause();
221                }
222                return true;
223            }
224            else if (ea.getKey()=='r')
225            {
226                std::cout<< _currentImageStream.get() << " Restart"<<std::endl;
227                _currentImageStream->rewind();
228                _currentImageStream->play();
229                return true;
230            }
231            else if (ea.getKey()=='>')
232            {
233                std::cout << _currentImageStream.get() << " Seeking"<<std::endl;
234                _currentImageStream->seek(_currentImageStream->getCurrentTime() + 1.0);
235               
236                return true;
237            }
238            else if (ea.getKey()=='L')
239            {
240                if ( _currentImageStream->getLoopingMode() == osg::ImageStream::LOOPING)
241                {
242                    std::cout<< _currentImageStream.get() << " Toggle Looping Off"<<std::endl;
243                    _currentImageStream->setLoopingMode( osg::ImageStream::NO_LOOPING );
244                }
245                else
246                {
247                    std::cout<< _currentImageStream.get() << " Toggle Looping On"<<std::endl;
248                    _currentImageStream->setLoopingMode( osg::ImageStream::LOOPING );
249                }
250                return true;
251            }
252            else if (ea.getKey()=='+')
253            {
254                double tm = _currentImageStream->getTimeMultiplier();
255                tm += 0.1;
256                _currentImageStream->setTimeMultiplier(tm);
257                std::cout << _currentImageStream.get() << " Increase speed rate "<< _currentImageStream->getTimeMultiplier() << std::endl;
258               
259                return true;
260            }
261            else if (ea.getKey()=='-')
262            {
263                double tm = _currentImageStream->getTimeMultiplier();
264                tm -= 0.1;
265                _currentImageStream->setTimeMultiplier(tm);
266                std::cout << _currentImageStream.get() << " Decrease speed rate "<< _currentImageStream->getTimeMultiplier() << std::endl;
267               
268                return true;
269            }
270            else if (ea.getKey()=='o')
271            {
272                std::cout<< _currentImageStream.get() << " Frame rate  "<< _currentImageStream->getFrameRate() <<std::endl;
273               
274                return true;
275            }
276            return false;
277        }
278
279        default:
280            return false;
281    }
282    return false;
283}
284
285void MovieEventHandler::getUsage(osg::ApplicationUsage& usage) const
286{
287    usage.addKeyboardMouseBinding("p","Play/Pause current movie");
288    usage.addKeyboardMouseBinding("r","Restart current movie");
289    usage.addKeyboardMouseBinding("l","Toggle looping of current movie");
290    usage.addKeyboardMouseBinding("+","Increase speed of current movie");
291    usage.addKeyboardMouseBinding("-","Decrease speed of current movie");
292    usage.addKeyboardMouseBinding("o","Display frame rate of current movie");
293    usage.addKeyboardMouseBinding(">","Advance the current movie using seek");
294}
295
296
297static osgDB::DirectoryContents getSuitableFiles(osg::ArgumentParser& arguments)
298{
299    osgDB::DirectoryContents files;
300    for(int i=1; i<arguments.argc(); ++i)
301    {
302        if (arguments.isOption(i))
303            continue;
304       
305        if (osgDB::fileType(arguments[i]) == osgDB::DIRECTORY)
306        {
307            const std::string& directory = arguments[i];
308            osgDB::DirectoryContents dc = osgDB::getSortedDirectoryContents(directory);
309           
310            for(osgDB::DirectoryContents::iterator itr = dc.begin(); itr != dc.end(); ++itr)
311            {
312                std::string full_file_name = directory + "/" + (*itr);
313                if (osgDB::fileType(full_file_name) != osgDB::DIRECTORY)
314                {
315                    files.push_back(full_file_name);
316                }
317            }
318        }
319        else {
320            files.push_back(arguments[i]);
321        }
322    }
323    return files;
324}
325
326
327class MyDimensionsChangedCallback : public osg::Image::DimensionsChangedCallback {
328public:
329    MyDimensionsChangedCallback(osg::Texture* tex, osg::Geometry* geo)
330        : osg::Image::DimensionsChangedCallback()
331        , _tex(tex)
332        , _geo(geo)
333    {
334    }
335   
336    virtual void operator()(osg::Image* img)
337    {
338        if (img && _tex.valid() && _geo.valid())
339        {
340            float l(0), t(0);
341            float r = (_tex->getTextureTarget() == GL_TEXTURE_2D) ? 1 : img->s();
342            float b = (_tex->getTextureTarget() == GL_TEXTURE_2D) ? 1 : img->t();
343           
344            /*
345            if (img->getOrigin() == osg::Image::TOP_LEFT)
346                std::swap(t, b);
347            */
348           
349            osg::Vec2Array* tex_coords = dynamic_cast<osg::Vec2Array*>(_geo->getTexCoordArray(0));
350            if (tex_coords) {
351               
352                (*tex_coords)[0].set(l,t);
353                (*tex_coords)[1].set(l,b);
354                (*tex_coords)[2].set(r,b);
355                (*tex_coords)[3].set(r,t);
356                tex_coords->dirty();
357                _geo->dirtyDisplayList();
358            }
359        }
360    }
361   
362private:
363    osg::observer_ptr<osg::Texture> _tex;
364    osg::observer_ptr<osg::Geometry> _geo;
365};
366
367static osg::Node* readImageStream(const std::string& file_name, osg::Vec3& p, float desired_height, osgDB::Options* options)
368{   
369    osg::ref_ptr<osg::Object> obj = osgDB::readObjectFile(file_name, options);
370    osg::ref_ptr<osg::Texture> tex = dynamic_cast<osg::Texture*>(obj.get());
371    osg::Geometry* geo(NULL);
372    float w(0);
373   
374    if (!tex)
375    {
376        osg::ref_ptr<osg::ImageStream> img_stream = dynamic_cast<osg::ImageStream*>(obj.get());
377       
378        // try readImageFile if readObjectFile failed
379        if (!img_stream)
380        {
381            img_stream = dynamic_cast<osg::ImageStream*>(osgDB::readImageFile(file_name, options));
382        }
383       
384        if (img_stream)
385        {
386            tex = new osg::Texture2D(img_stream.get());
387            tex->setResizeNonPowerOfTwoHint(false);
388           
389        }
390    }
391   
392    // create textured quad
393    if(tex)
394    {
395        osg::Geode* geode = new osg::Geode();
396       
397        osg::ref_ptr<osg::ImageStream> img = dynamic_cast<osg::ImageStream*>(tex->getImage(0));
398        if (img)
399        {
400            w = (img->t() > 0) ? img->s() * desired_height / img->t() : 0;
401           
402            osgText::Text* text = new osgText::Text();
403            text->setFont("arial.ttf");
404            text->setDataVariance(osg::Object::DYNAMIC);
405            text->setUpdateCallback(new ImageStreamStateCallback(text, img.get()));
406            text->setCharacterSize(24);
407            text->setPosition(p + osg::Vec3(10,-10,10));
408            text->setAxisAlignment(osgText::TextBase::XZ_PLANE);
409            geode->addDrawable (text);
410        }
411       
412        if (w == 0)
413        {
414            // hmm, imagestream with no width?
415            w = desired_height * 16 / 9.0f;
416        }
417        float tex_s = (tex->getTextureTarget() == GL_TEXTURE_2D) ? 1 : img->s();
418        float tex_t = (tex->getTextureTarget() == GL_TEXTURE_2D) ? 1 : img->t();
419       
420        if (img->getOrigin() == osg::Image::TOP_LEFT)
421            geo = osg::createTexturedQuadGeometry(p, osg::Vec3(w, 0, 0), osg::Vec3(0, 0, desired_height), 0, tex_t, tex_s, 0);
422        else
423            geo = osg::createTexturedQuadGeometry(p, osg::Vec3(w, 0, 0), osg::Vec3(0, 0, desired_height), 0, 0, tex_s, tex_t);
424       
425        geode->addDrawable(geo);
426
427        geo->getOrCreateStateSet()->setTextureAttributeAndModes(0, tex.get());
428       
429        osg::Vec4Array* colors = new osg::Vec4Array();
430        colors->push_back(osg::Vec4(0.7, 0.7, 0.7, 1));
431       
432        geo->setColorArray(colors);
433        geo->setColorBinding(osg::Geometry::BIND_OVERALL);
434       
435        p[0] += w + 10;
436       
437        img->addDimensionsChangedCallback(new MyDimensionsChangedCallback(tex.get(), geo));
438       
439        return geode;
440    }
441    else
442    {
443        std::cout << "could not read file from " << file_name << std::endl;
444        return NULL;
445    }
446   
447    return NULL;
448}
449
450
451class ReplaceTextureVisitor : public osg::NodeVisitor {
452public:
453    ReplaceTextureVisitor(osg::Texture* tex)
454        : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
455        , _tex(tex)
456    {
457    }
458   
459    virtual void apply(osg::Geode& geode)
460    {
461        apply(geode.getStateSet());
462        for(unsigned int i = 0; i < geode.getNumDrawables(); ++i)
463        {
464            osg::Drawable* drawable = geode.getDrawable(i);
465           
466            apply(drawable->getStateSet());
467            ImageStreamStateCallback* cb = dynamic_cast<ImageStreamStateCallback*>(drawable->getUpdateCallback());
468            if (cb)
469                cb->setImageStream(dynamic_cast<osg::ImageStream*>(_tex->getImage(0)));
470               
471        }
472       
473        osg::NodeVisitor::apply(geode);
474    }
475   
476    void apply(osg::StateSet* ss)
477    {
478        if (ss && ss->getTextureAttribute(0, osg::StateAttribute::TEXTURE))
479            ss->setTextureAttribute(0, _tex.get());
480    }
481private:
482    osg::ref_ptr<osg::Texture> _tex;
483};
484
485
486class SlideShowEventHandler : public osgGA::GUIEventHandler {
487public:
488    SlideShowEventHandler(osg::Node* node, const osgDB::DirectoryContents& files,osgDB::ReaderWriter::Options* options)
489        : osgGA::GUIEventHandler()
490        , _node(node)
491        , _files(files)
492        , _options(options)
493        , _currentFile(-1)
494    {
495        loadSlide(_currentFile);
496    }
497   
498    bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa, osg::Object*, osg::NodeVisitor* nv)
499    {
500        switch(ea.getEventType())
501        {
502            case(osgGA::GUIEventAdapter::KEYDOWN):
503                {
504                    if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Left)
505                        loadSlide(_currentFile - 1);
506                    else if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Right)
507                        loadSlide(_currentFile + 1);
508                    else
509                        return false;
510                   
511                    return true;
512                }
513                break;
514            default:
515                break;
516        }
517       
518        return false;
519    }
520   
521private:
522   
523    void loadSlide(int new_ndx)
524    {
525        if (new_ndx == _currentFile)
526            return;
527       
528        _currentFile = new_ndx;
529        if (_currentFile < 0)
530            _currentFile = _files.size() - 1;
531        else if (_currentFile >= static_cast<int>(_files.size()))
532            _currentFile = 0;
533       
534        osg::ref_ptr<osg::Object> obj = osgDB::readRefObjectFile(_files[_currentFile], _options.get());
535        osg::ref_ptr<osg::Texture> tex = dynamic_cast<osg::Texture*>(obj.get());
536        if (!tex) {
537            osg::ref_ptr<osg::ImageStream> stream = dynamic_cast<osg::ImageStream*>(obj.get());
538            if (!stream)
539                stream = dynamic_cast<osg::ImageStream*>(osgDB::readImageFile(_files[_currentFile], _options.get()));
540           
541            if (stream)
542            {
543                tex = new osg::Texture2D(stream.get());
544                tex->setResizeNonPowerOfTwoHint(false);
545            }
546        }
547        if (tex) {
548            osg::ref_ptr<osg::ImageStream> stream = dynamic_cast<osg::ImageStream*>(tex->getImage(0));
549            if (stream)
550                stream->play();
551            ReplaceTextureVisitor v(tex.get());
552            _node->accept(v);
553        }
554    }
555
556    osg::ref_ptr<osg::Node> _node;
557    osgDB::DirectoryContents _files;
558    osg::ref_ptr<osgDB::ReaderWriter::Options> _options;
559    int _currentFile;
560};
561
562
563int main(int argc, char** argv)
564{
565    /*
566    std::string plugin_to_use = "AVFoundation"; //  "QTKit";
567   
568    osgDB::Registry::instance()->addFileExtensionAlias("mov", plugin_to_use);
569    osgDB::Registry::instance()->addFileExtensionAlias("mp4", plugin_to_use);
570    osgDB::Registry::instance()->addFileExtensionAlias("m4v", plugin_to_use);
571    */
572   
573    // use an ArgumentParser object to manage the program arguments.
574    osg::ArgumentParser arguments(&argc,argv);
575
576    // set up the usage document, in case we need to print out how to use this program.
577    arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
578    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" example demonstrates the use of ImageStream for rendering movies as textures.");
579    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
580    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
581    arguments.getApplicationUsage()->addCommandLineOption("--disableCoreVideo","disable CoreVideo (QTKit+AVFoundation plugin)");
582    arguments.getApplicationUsage()->addCommandLineOption("--disableMultiThreadedFrameDispatching","disable frame dispatching via multiple threads (QTKit+AVFoundation plugin)");
583    arguments.getApplicationUsage()->addCommandLineOption("--maxVideos [numVideos]","max videos to open from a folder");
584    arguments.getApplicationUsage()->addCommandLineOption("--slideShow","present movies in a slide-show");
585   
586    unsigned int max_videos(10);
587    bool slide_show = false;
588    std::string options_str("");
589   
590    if (arguments.find("--slideShow") > 0) {
591        slide_show = true;
592    }
593   
594    if (arguments.find("--disableMultiThreadedFrameDispatching") > 0) {
595        options_str += " disableMultiThreadedFrameDispatching";
596    }
597   
598    if (arguments.find("--disableCoreVideo") > 0) {
599        options_str += " disableCoreVideo";
600    }
601   
602    if (int ndx = arguments.find("--numFrameDispatchThreads") > 0)
603    {
604        options_str += std::string(" numFrameDispatchThreads=") + arguments[ndx+1];
605    }
606    if (int ndx = arguments.find("--maxVideos") > 0)
607    {
608        if (arguments.isNumber(ndx+1)) max_videos =  atoi(arguments[ndx+1]);
609    }
610
611
612    // construct the viewer.
613    osgViewer::Viewer viewer(arguments);
614   
615    if (arguments.argc()<=1)
616    {
617        arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
618        return 1;
619    }
620   
621
622    // if user request help write it out to cout.
623    if (arguments.read("-h") || arguments.read("--help"))
624    {
625        arguments.getApplicationUsage()->write(std::cout);
626        return 1;
627    }
628
629
630    osg::ref_ptr<osg::Group> group = new osg::Group;
631
632    osg::StateSet* stateset = group->getOrCreateStateSet();
633    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
634
635   
636    osg::Vec3 pos(0.0f,0.0f,0.0f);
637    static const float desired_height = 768.0f;
638   
639    osgDB::DirectoryContents files = getSuitableFiles(arguments);
640    osgGA::GUIEventHandler* movie_event_handler(NULL);
641   
642    osg::ref_ptr<osgDB::ReaderWriter::Options> options = new osgDB::ReaderWriter::Options(options_str);
643   
644    if (slide_show)
645    {
646        osg::Node* node = readImageStream(files[0], pos, desired_height, options.get());
647        group->addChild(node);
648        movie_event_handler = new SlideShowEventHandler(node, files, options.get());
649    }
650    else
651    {
652        movie_event_handler = new MovieEventHandler();
653
654        unsigned int num_files_per_row = std::max(osg::round(sqrt(static_cast<double>(std::min(max_videos, static_cast<unsigned int>(files.size()))))), 1.0);
655        static const float new_row_at = num_files_per_row * desired_height * 16 / 9.0;
656               
657        unsigned int num_videos = 0;
658        for(osgDB::DirectoryContents::iterator i = files.begin(); (i != files.end()) && (num_videos < max_videos); ++i)
659        {
660            osg::Node* node = readImageStream(*i, pos, desired_height, options.get());
661            if (node)
662                group->addChild(node);
663           
664            if (pos[0] > new_row_at)
665            {
666                pos[0] = 0;
667                pos[2] += desired_height +10;
668            }
669            num_videos++;
670        }
671    }
672
673
674    // set the scene to render
675    viewer.setSceneData(group.get());
676
677    if (viewer.getSceneData()==0)
678    {
679        arguments.getApplicationUsage()->write(std::cout);
680        return 1;
681    }
682   
683   
684    viewer.addEventHandler( movie_event_handler );
685    viewer.addEventHandler( new osgViewer::StatsHandler );
686    viewer.addEventHandler( new osgViewer::ToggleSyncToVBlankHandler());
687    viewer.addEventHandler( new osgGA::StateSetManipulator( viewer.getCamera()->getOrCreateStateSet() ) );
688    viewer.addEventHandler( new osgViewer::WindowSizeHandler );
689
690    // add the record camera path handler
691    viewer.addEventHandler(new osgViewer::RecordCameraPathHandler);
692
693    // report any errors if they have occurred when parsing the program arguments.
694    if (arguments.errors())
695    {
696        arguments.writeErrorMessages(std::cout);
697        return 1;
698    }
699
700    // create the windows and run the threads.
701    return viewer.run();
702}
Note: See TracBrowser for help on using the browser.