root/OpenSceneGraph/trunk/examples/osgimagesequence/osgimagesequence.cpp @ 13338

Revision 13191, 15.3 kB (checked in by robert, 12 hours ago)

From Jason Beverage, "It looks like the Callback header got accidentally removed from the CMakeLists.txt in the submission yesterday for the geometry instancing example."

  • Property svn:eol-style set to native
Line 
1/* OpenSceneGraph example, osgtexture3D.
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 <osg/Node>
20#include <osg/Geometry>
21#include <osg/Notify>
22#include <osg/Texture1D>
23#include <osg/Texture2D>
24#include <osg/Texture3D>
25#include <osg/TextureRectangle>
26#include <osg/ImageSequence>
27#include <osg/Geode>
28
29#include <osgDB/Registry>
30#include <osgDB/ReadFile>
31#include <osgDB/WriteFile>
32#include <osgDB/FileNameUtils>
33#include <osgDB/FileUtils>
34
35
36#include <osgViewer/Viewer>
37#include <osgViewer/ViewerEventHandlers>
38
39#include <iostream>
40
41
42static osgDB::DirectoryContents getSuitableFiles(osg::ArgumentParser& arguments)
43{
44    osgDB::DirectoryContents files;
45    for(int i=1; i<arguments.argc(); ++i)
46    {
47        if (osgDB::fileType(arguments[i]) == osgDB::DIRECTORY)
48        {
49            const std::string& directory = arguments[i];
50            osgDB::DirectoryContents dc = osgDB::getSortedDirectoryContents(directory);
51           
52            for(osgDB::DirectoryContents::iterator itr = dc.begin(); itr != dc.end(); ++itr)
53            {
54                std::string full_file_name = directory + "/" + (*itr);
55                std::string ext = osgDB::getLowerCaseFileExtension(full_file_name);
56                if ((ext == "jpg") || (ext == "png") || (ext == "gif") ||  (ext == "rgb") || (ext == "dds") )
57                {
58                    files.push_back(full_file_name);
59                }
60            }
61        }
62        else {
63            files.push_back(arguments[i]);
64        }
65    }
66    return files;
67}
68
69
70//
71// A simple demo demonstrating how to set on an animated texture using an osg::ImageSequence
72//
73
74osg::StateSet* createState(osg::ArgumentParser& arguments)
75{
76    osg::ref_ptr<osg::ImageSequence> imageSequence = new osg::ImageSequence;
77
78    bool preLoad = true;
79       
80    while (arguments.read("--page-and-discard"))
81    {
82        imageSequence->setMode(osg::ImageSequence::PAGE_AND_DISCARD_USED_IMAGES);
83        preLoad = false;
84    }
85   
86    while (arguments.read("--page-and-retain"))
87    {
88        imageSequence->setMode(osg::ImageSequence::PAGE_AND_RETAIN_IMAGES);
89        preLoad = false;
90    }
91   
92    while (arguments.read("--preload"))
93    {
94        imageSequence->setMode(osg::ImageSequence::PRE_LOAD_ALL_IMAGES);
95        preLoad = true;
96    }
97   
98    double length = -1.0;
99    while (arguments.read("--length",length)) {}
100   
101    double fps = 30.0;
102    while (arguments.read("--fps",fps)) {}
103
104    osgDB::DirectoryContents files = getSuitableFiles(arguments);
105    if (!files.empty())
106    {
107        for(osgDB::DirectoryContents::iterator itr = files.begin();
108            itr != files.end();
109            ++itr)
110        {
111            const std::string& filename = *itr;
112            if (preLoad)
113            {
114                osg::ref_ptr<osg::Image> image = osgDB::readImageFile(filename);
115                if (image.valid())
116                {
117                    imageSequence->addImage(image.get());
118                }
119            }
120            else
121            {
122                imageSequence->addImageFile(filename);
123            }
124
125        }
126       
127        if (length>0.0)
128        {
129            imageSequence->setLength(length);
130        }
131        else
132        {
133            unsigned int maxNum = imageSequence->getNumImageData();
134            imageSequence->setLength(double(maxNum)*(1.0/fps));
135        }
136    }
137    else
138    {
139        if (length>0.0)
140        {
141            imageSequence->setLength(length);
142        }
143        else
144        {
145            imageSequence->setLength(4.0);
146        }
147        imageSequence->addImage(osgDB::readImageFile("Cubemap_axis/posx.png"));
148        imageSequence->addImage(osgDB::readImageFile("Cubemap_axis/negx.png"));
149        imageSequence->addImage(osgDB::readImageFile("Cubemap_axis/posy.png"));
150        imageSequence->addImage(osgDB::readImageFile("Cubemap_axis/negy.png"));
151        imageSequence->addImage(osgDB::readImageFile("Cubemap_axis/posz.png"));
152        imageSequence->addImage(osgDB::readImageFile("Cubemap_axis/negz.png"));
153    }
154       
155    // start the image sequence playing
156    imageSequence->play();
157
158#if 1
159    osg::Texture2D* texture = new osg::Texture2D;
160    texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);
161    texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR);
162    texture->setWrap(osg::Texture::WRAP_R,osg::Texture::REPEAT);
163    texture->setResizeNonPowerOfTwoHint(false);
164    texture->setImage(imageSequence.get());
165    //texture->setTextureSize(512,512);
166#else   
167    osg::TextureRectangle* texture = new osg::TextureRectangle;
168    texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);
169    texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR);
170    texture->setWrap(osg::Texture::WRAP_R,osg::Texture::REPEAT);
171    texture->setImage(imageSequence.get());
172    //texture->setTextureSize(512,512);
173#endif
174
175    // create the StateSet to store the texture data
176    osg::StateSet* stateset = new osg::StateSet;
177
178    stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
179
180    return stateset;
181}
182
183osg::Node* createModel(osg::ArgumentParser& arguments)
184{
185
186    // create the geometry of the model, just a simple 2d quad right now.   
187    osg::Geode* geode = new osg::Geode;
188    geode->addDrawable(osg::createTexturedQuadGeometry(osg::Vec3(0.0f,0.0f,0.0), osg::Vec3(1.0f,0.0f,0.0), osg::Vec3(0.0f,0.0f,1.0f)));
189
190    geode->setStateSet(createState(arguments));
191   
192    return geode;
193
194}
195
196
197osg::ImageStream* s_imageStream = 0;
198class MovieEventHandler : public osgGA::GUIEventHandler
199{
200public:
201
202    MovieEventHandler():_playToggle(true),_trackMouse(false) {}
203   
204    void setMouseTracking(bool track) { _trackMouse = track; }
205    bool getMouseTracking() const { return _trackMouse; }
206   
207    void set(osg::Node* node);
208
209    void setTrackMouse(bool tm)
210    {
211        if (tm==_trackMouse) return;
212
213        _trackMouse = tm;
214
215        std::cout << "tracking mouse: " << (_trackMouse ? "ON" : "OFF") << std::endl;
216
217        for(ImageStreamList::iterator itr=_imageStreamList.begin();
218            itr!=_imageStreamList.end();
219            ++itr)
220        {
221            if ((*itr)->getStatus()==osg::ImageStream::PLAYING)
222            {
223                (*itr)->pause();
224            }
225            else
226            {
227                (*itr)->play();
228            }
229        }
230
231    }
232
233    bool getTrackMouse() const { return _trackMouse; }
234
235    virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa, osg::Object*, osg::NodeVisitor* nv);
236   
237    virtual void getUsage(osg::ApplicationUsage& usage) const;
238
239    typedef std::vector< osg::observer_ptr<osg::ImageStream> > ImageStreamList;
240   
241    struct ImageStreamPlaybackSpeedData {
242        double fps;
243        unsigned char* lastData;
244        double timeStamp, lastOutput;
245       
246        ImageStreamPlaybackSpeedData() : fps(0), lastData(NULL), timeStamp(0), lastOutput(0) {}
247       
248    };
249   
250    typedef std::vector< ImageStreamPlaybackSpeedData > ImageStreamPlayBackSpeedList;
251
252protected:
253
254    virtual ~MovieEventHandler() {}
255
256    class FindImageStreamsVisitor : public osg::NodeVisitor
257    {
258    public:
259        FindImageStreamsVisitor(ImageStreamList& imageStreamList):
260            _imageStreamList(imageStreamList) {}
261           
262        virtual void apply(osg::Geode& geode)
263        {
264            apply(geode.getStateSet());
265
266            for(unsigned int i=0;i<geode.getNumDrawables();++i)
267            {
268                apply(geode.getDrawable(i)->getStateSet());
269            }
270       
271            traverse(geode);
272        }
273
274        virtual void apply(osg::Node& node)
275        {
276            apply(node.getStateSet());
277            traverse(node);
278        }
279       
280        inline void apply(osg::StateSet* stateset)
281        {
282            if (!stateset) return;
283           
284            osg::StateAttribute* attr = stateset->getTextureAttribute(0,osg::StateAttribute::TEXTURE);
285            if (attr)
286            {
287                osg::Texture2D* texture2D = dynamic_cast<osg::Texture2D*>(attr);
288                if (texture2D) apply(dynamic_cast<osg::ImageStream*>(texture2D->getImage()));
289
290                osg::TextureRectangle* textureRec = dynamic_cast<osg::TextureRectangle*>(attr);
291                if (textureRec) apply(dynamic_cast<osg::ImageStream*>(textureRec->getImage()));
292            }
293        }
294       
295        inline void apply(osg::ImageStream* imagestream)
296        {
297            if (imagestream)
298            {
299                _imageStreamList.push_back(imagestream);
300                s_imageStream = imagestream;
301            }
302        }
303       
304        ImageStreamList& _imageStreamList;
305       
306    protected:
307   
308        FindImageStreamsVisitor& operator = (const FindImageStreamsVisitor&) { return *this; }
309    };
310
311
312    bool            _playToggle;
313    bool            _trackMouse;
314    ImageStreamList _imageStreamList;
315    ImageStreamPlayBackSpeedList _imageStreamPlayBackSpeedList;
316   
317};
318
319
320
321void MovieEventHandler::set(osg::Node* node)
322{
323    _imageStreamList.clear();
324    if (node)
325    {
326        FindImageStreamsVisitor fisv(_imageStreamList);
327        node->accept(fisv);
328    }
329    _imageStreamPlayBackSpeedList.resize(_imageStreamList.size());
330}
331
332
333bool MovieEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa, osg::Object*, osg::NodeVisitor* nv)
334{
335    switch(ea.getEventType())
336    {
337        case(osgGA::GUIEventAdapter::FRAME):
338            {
339                double t = ea.getTime();
340                bool printed(false);
341               
342                ImageStreamPlayBackSpeedList::iterator fps_itr = _imageStreamPlayBackSpeedList.begin();
343                for(ImageStreamList::iterator itr=_imageStreamList.begin();
344                    itr!=_imageStreamList.end();
345                    ++itr, ++fps_itr)
346                {
347                    if (((*itr)->getStatus()==osg::ImageStream::PLAYING) && ((*itr)->data() != (*fps_itr).lastData))
348                    {
349                        ImageStreamPlaybackSpeedData& data(*fps_itr);
350                        double dt = (data.timeStamp > 0) ? t - data.timeStamp : 1/60.0;
351                        data.lastData = (*itr)->data();
352                        data.fps = (*fps_itr).fps * 0.8 + 0.2 * (1/dt);
353                        data.timeStamp = t;
354                       
355                        if (t-data.lastOutput > 1)
356                        {
357                            std::cout << data.fps << " ";
358                            data.lastOutput = t;
359                            printed = true;
360                        }
361                       
362                    }
363                }
364                if (printed)
365                    std::cout << std::endl;
366            }
367            break;
368        case(osgGA::GUIEventAdapter::MOVE):
369            {
370                if (_trackMouse)
371                {
372                    for(ImageStreamList::iterator itr=_imageStreamList.begin();
373                        itr!=_imageStreamList.end();
374                        ++itr)
375                    {
376                        double dt = (*itr)->getLength() * ((1.0+ea.getXnormalized()) / 2.0);
377                        (*itr)->seek(dt);
378                        std::cout << "seeking to " << dt << " length: " <<(*itr)->getLength() << std::endl;
379                    }
380                }
381                return false;
382            }
383           
384        case(osgGA::GUIEventAdapter::KEYDOWN):
385        {
386            if (ea.getKey()=='p')
387            {
388                for(ImageStreamList::iterator itr=_imageStreamList.begin();
389                    itr!=_imageStreamList.end();
390                    ++itr)
391                {
392                    if ((*itr)->getStatus()==osg::ImageStream::PLAYING)
393                    {
394                        // playing, so pause
395                        std::cout<<"Pause"<<std::endl;
396                        (*itr)->pause();
397                    }
398                    else
399                    {
400                        // playing, so pause
401                        std::cout<<"Play"<<std::endl;
402                        (*itr)->play();
403                    }
404                }
405                return true;
406            }
407            else if (ea.getKey()=='r')
408            {
409                for(ImageStreamList::iterator itr=_imageStreamList.begin();
410                    itr!=_imageStreamList.end();
411                    ++itr)
412                {
413                    std::cout<<"Restart"<<std::endl;
414                    (*itr)->rewind();
415                }
416                return true;
417            }
418            else if (ea.getKey()=='L')
419            {
420                for(ImageStreamList::iterator itr=_imageStreamList.begin();
421                    itr!=_imageStreamList.end();
422                    ++itr)
423                {
424                    if ( (*itr)->getLoopingMode() == osg::ImageStream::LOOPING)
425                    {
426                        std::cout<<"Toggle Looping Off"<<std::endl;
427                        (*itr)->setLoopingMode( osg::ImageStream::NO_LOOPING );
428                    }
429                    else
430                    {
431                        std::cout<<"Toggle Looping On"<<std::endl;
432                        (*itr)->setLoopingMode( osg::ImageStream::LOOPING );
433                    }
434                }
435                return true;
436            }
437            else if (ea.getKey() == 'i')
438            {
439                setTrackMouse(!_trackMouse);
440               
441               
442            }
443            return false;
444        }
445
446        default:
447            return false;
448    }
449
450    return false;
451}
452
453void MovieEventHandler::getUsage(osg::ApplicationUsage& usage) const
454{
455    usage.addKeyboardMouseBinding("i","toggle interactive mode, scrub via mouse-move");
456    usage.addKeyboardMouseBinding("p","Play/Pause movie");
457    usage.addKeyboardMouseBinding("r","Restart movie");
458    usage.addKeyboardMouseBinding("l","Toggle looping of movie");
459}
460
461
462
463
464int main(int argc, char **argv)
465{
466    osg::ArgumentParser arguments(&argc,argv);
467
468    // construct the viewer.
469    osgViewer::Viewer viewer(arguments);
470
471    std::string filename;
472    arguments.read("-o",filename);
473
474    // create a model from the images and pass it to the viewer.
475    viewer.setSceneData(createModel(arguments));
476
477    // pass the model to the MovieEventHandler so it can pick out ImageStream's to manipulate.
478    MovieEventHandler* meh = new MovieEventHandler();
479    meh->set( viewer.getSceneData() );
480
481    if (arguments.read("--track-mouse")) meh->setTrackMouse(true);
482   
483    viewer.addEventHandler( meh );
484
485    viewer.addEventHandler( new osgViewer::StatsHandler());
486
487    if (!filename.empty())
488    {
489        osgDB::writeNodeFile(*viewer.getSceneData(),filename);
490    }
491
492    return viewer.run();
493}
Note: See TracBrowser for help on using the browser.