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

Revision 13191, 15.3 kB (checked in by robert, 4 days ago)

Added shaders to support experimental shader based displacement mapping technique osgTerrain::ShaderTerrain?.

  • 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.