root/OpenSceneGraph/trunk/examples/osgphotoalbum/osgphotoalbum.cpp @ 2521

Revision 2521, 16.3 kB (checked in by robert, 10 years ago)

Added proper handling of unhandled file return type.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under 
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14#include <osgProducer/Viewer>
15#include <osgDB/ReadFile>
16#include <osgDB/WriteFile>
17#include <osgDB/ImageOptions>
18
19#include <osgUtil/Optimizer>
20
21#include <osg/Geode>
22#include <osg/Notify>
23#include <osg/MatrixTransform>
24#include <osg/Switch>
25#include <osg/TexMat>
26#include <osg/Texture2D>
27#include <osg/PolygonOffset>
28
29#include <osgText/Text>
30
31#include <sstream>
32
33class ImageReaderWriter : public osgDB::ReaderWriter
34{
35    public:
36        virtual const char* className() { return "Image Reader"; }
37       
38       
39        struct DataReference
40        {
41            DataReference():
42                _fileName(),
43                _resolutionX(256),
44                _resolutionY(256),
45                _center(0.0f,0.0f,0.0f),
46                _maximumWidth(1.25f,0.0f,0.0f),
47                _maximumHeight(0.0f,0.0f,1.0f),
48                _numPointsAcross(10),
49                _numPointsUp(10) {}
50
51            DataReference(const std::string& fileName, unsigned int res):
52                _fileName(fileName),
53                _resolutionX(res),
54                _resolutionY(res),
55                _center(0.0f,0.0f,0.0f),
56                _maximumWidth(1.25f,0.0f,0.0f),
57                _maximumHeight(0.0f,0.0f,1.0f),
58                _numPointsAcross(10),
59                _numPointsUp(10) {}
60       
61            DataReference(const DataReference& rhs):
62                _fileName(rhs._fileName),
63                _resolutionX(rhs._resolutionX),
64                _resolutionY(rhs._resolutionY),
65                _center(rhs._center),
66                _maximumWidth(rhs._maximumWidth),
67                _maximumHeight(rhs._maximumHeight),
68                _numPointsAcross(rhs._numPointsAcross),
69                _numPointsUp(rhs._numPointsUp) {}
70
71            std::string     _fileName;
72            unsigned int    _resolutionX;
73            unsigned int    _resolutionY;
74            osg::Vec3       _center;
75            osg::Vec3       _maximumWidth;
76            osg::Vec3       _maximumHeight;
77            unsigned int    _numPointsAcross;
78            unsigned int    _numPointsUp;
79        };
80       
81        typedef std::map<std::string,DataReference> DataReferenceMap;
82        DataReferenceMap _dataReferences;
83       
84        std::string insertReference(const std::string& fileName, unsigned int res)
85        {
86            std::stringstream ostr;
87            ostr<<"res_"<<res<<"_"<<fileName;
88
89            std::string myReference = ostr.str();
90            _dataReferences[myReference] = DataReference(fileName,res);
91            return myReference;
92        }
93       
94       
95
96        virtual ReadResult readNode(const std::string& fileName, const Options* opt)
97        {
98            std::cout<<"Trying to read paged image "<<fileName<<std::endl;
99           
100            DataReferenceMap::iterator itr = _dataReferences.find(fileName);
101            if (itr==_dataReferences.end()) return ReaderWriter::ReadResult::FILE_NOT_HANDLED;
102
103            DataReference& dr = itr->second;
104           
105            // record previous options.
106            osg::ref_ptr<osgDB::ReaderWriter::Options> previousOptions = osgDB::Registry::instance()->getOptions();
107
108            osg::ref_ptr<osgDB::ImageOptions> options = new osgDB::ImageOptions;
109            options->_destinationImageWindowMode = osgDB::ImageOptions::PIXEL_WINDOW;
110            options->_destinationPixelWindow.set(0,0,dr._resolutionX,dr._resolutionY);
111
112            osgDB::Registry::instance()->setOptions(options.get());
113           
114            osg::Image* image = osgDB::readImageFile(dr._fileName);
115           
116            // restore previous options.
117            osgDB::Registry::instance()->setOptions(previousOptions.get());
118
119            if (image)
120            {
121           
122                float s = options.valid()?options->_sourcePixelWindow.windowWidth:1.0f;
123                float t = options.valid()?options->_sourcePixelWindow.windowHeight:1.0f;
124           
125                osg::Geode* geode = osg::createGeodeForImage(image,s,t);
126                return geode;
127           
128            }
129            else
130            {
131                return ReaderWriter::ReadResult::FILE_NOT_HANDLED;
132            }
133           
134                       
135        }
136
137};
138
139
140// now register with Registry to instantiate the above
141// reader/writer.
142osgDB::RegisterReaderWriterProxy<ImageReaderWriter> g_ImageReaderWriter;
143
144
145
146typedef std::vector<std::string> FileList;
147
148class SlideEventHandler : public osgGA::GUIEventHandler, public osg::NodeCallback
149{
150public:
151
152    SlideEventHandler();
153   
154    META_Object(osgStereImageApp,SlideEventHandler);
155
156    void set(osg::Switch* sw, float timePerSlide, bool autoSteppingActive);
157
158    virtual void accept(osgGA::GUIEventHandlerVisitor& v) { v.visit(*this); }
159
160    virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&);
161   
162    virtual void getUsage(osg::ApplicationUsage& usage) const;
163
164    virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
165   
166    void nextSlide();
167   
168    void previousSlide();
169
170protected:
171
172    ~SlideEventHandler() {}
173    SlideEventHandler(const SlideEventHandler&,const osg::CopyOp&) {}
174
175    osg::ref_ptr<osg::Switch>   _switch;
176    bool                        _firstTraversal;
177    unsigned int                _activeSlide;
178    double                      _previousTime;
179    double                      _timePerSlide;
180    bool                        _autoSteppingActive;
181};
182
183SlideEventHandler::SlideEventHandler():
184    _switch(0),
185    _firstTraversal(true),
186    _activeSlide(0),
187    _previousTime(-1.0f),
188    _timePerSlide(5.0),
189    _autoSteppingActive(false)
190{
191}
192
193void SlideEventHandler::set(osg::Switch* sw, float timePerSlide, bool autoSteppingActive)
194{
195    _switch = sw;
196    _switch->setUpdateCallback(this);
197
198    _timePerSlide = timePerSlide;
199    _autoSteppingActive = autoSteppingActive;   
200   
201}
202
203bool SlideEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&)
204{
205    switch(ea.getEventType())
206    {
207        case(osgGA::GUIEventAdapter::KEYDOWN):
208        {
209            if (ea.getKey()=='a')
210            {
211                _autoSteppingActive = !_autoSteppingActive;
212                _previousTime = ea.time();
213                return true;
214            }
215            else if (ea.getKey()=='n')
216            {
217                nextSlide();
218                return true;
219            }
220            else if (ea.getKey()=='p')
221            {
222                previousSlide();
223                return true;
224            }
225            return false;
226        }
227
228        default:
229            return false;
230    }
231}
232
233void SlideEventHandler::getUsage(osg::ApplicationUsage& usage) const
234{
235    usage.addKeyboardMouseBinding("Space","Reset the image position to center");
236    usage.addKeyboardMouseBinding("a","Toggle on/off the automatic advancement for image to image");
237    usage.addKeyboardMouseBinding("n","Advance to next image");
238    usage.addKeyboardMouseBinding("p","Move to previous image");
239}
240
241void SlideEventHandler::operator()(osg::Node* node, osg::NodeVisitor* nv)
242{
243    if (_autoSteppingActive && nv->getFrameStamp())
244    {
245        double time = nv->getFrameStamp()->getReferenceTime();
246       
247        if (_firstTraversal)
248        {
249            _firstTraversal = false;
250            _previousTime = time;
251        }
252        else if (time-_previousTime>_timePerSlide)
253        {
254            _previousTime = time;
255           
256            nextSlide();
257        }
258       
259    }
260
261    traverse(node,nv);
262}
263
264void SlideEventHandler::nextSlide()
265{
266    if (_switch->getNumChildren()==0) return;
267
268    ++_activeSlide;
269    if (_activeSlide>=_switch->getNumChildren()) _activeSlide = 0;
270
271    _switch->setSingleChildOn(_activeSlide);
272}
273
274void SlideEventHandler::previousSlide()
275{
276    if (_switch->getNumChildren()==0) return;
277
278    if (_activeSlide==0) _activeSlide = _switch->getNumChildren()-1;
279    else --_activeSlide;
280
281    _switch->setSingleChildOn(_activeSlide);
282}
283
284// create a switch containing a set of child each containing a
285// stereo image pair.
286osg::Switch* createScene(const FileList& fileList, float height, float length)
287{
288    osgDB::ReaderWriter* readerWriter = osgDB::Registry::instance()->getReaderWriterForExtension("gdal");
289    if (!readerWriter)
290    {
291        std::cout<<"Error: GDAL plugin not available, cannot preceed with database creation"<<std::endl;
292        return 0;
293    }
294
295    ImageReaderWriter* rw = g_ImageReaderWriter.get();
296
297    osg::Switch* sw = new osg::Switch;
298
299    typedef std::vector< osg::ref_ptr<osg::Node> > NodeList;
300    NodeList nodes;
301
302    // load the images.
303    unsigned int i;
304    for(i=0;i<fileList.size();++i)
305    {
306        float cut_off_distance = 8.0f;
307        float max_visible_distance = 300.0f;
308       
309        osg::Vec3 center(0.0f,0.0f,0.0f);
310
311        osgText::Text* text = new osgText::Text;
312        text->setFont("fonts/arial.ttf");
313        text->setPosition(center);
314        text->setCharacterSize(0.1f);
315        text->setAlignment(osgText::Text::CENTER_CENTER);
316        text->setAxisAlignment(osgText::Text::XZ_PLANE);
317        text->setText(fileList[i]);
318
319        osg::Geode* geode = new osg::Geode;
320        geode->addDrawable(text);
321       
322        osg::PagedLOD* pagedlod = new osg::PagedLOD;
323        pagedlod->setCenter(center);
324        pagedlod->setRadius(1.6f);
325        pagedlod->setNumChildrenThatCannotBeExpired(2);
326       
327        pagedlod->setRange(0,max_visible_distance,1e7);
328        pagedlod->addChild(geode);
329       
330        pagedlod->setRange(1,cut_off_distance,max_visible_distance);
331        pagedlod->setFileName(1,rw->insertReference(fileList[i],128));
332
333        pagedlod->setRange(2,0.0f,cut_off_distance);
334        pagedlod->setFileName(2,rw->insertReference(fileList[i],1024));
335
336        nodes.push_back(pagedlod);
337    }
338
339
340    if (nodes.empty()) return 0;
341   
342    osg::Group* front = new osg::Group;
343    sw->addChild(front);
344   
345    unsigned int nodes_across = (unsigned int)ceilf(sqrtf((float)nodes.size()*1.25));
346    unsigned int nodes_down = (unsigned int)ceilf((float)nodes.size()/(float)nodes_across);
347   
348    float scale = 1.0f/(float)nodes_down;
349   
350    osg::Vec3 down_delta(0.0f,0.0f,-scale);
351    osg::Vec3 across_delta(scale*1.25,0.0f,0.0f);
352    osg::Vec3 leftMargin(-down_delta*((float)nodes_down*0.5f)-across_delta*((float)nodes_across*0.5f));
353
354    osg::Vec3 pos = leftMargin;
355    i=0;
356   
357    // front cover background
358    {
359        osg::Geometry* geometry = createTexturedQuadGeometry(osg::Vec3(-1.25f,0.0f,-1.0f),osg::Vec3(2.5f,0.0f,0.0f),osg::Vec3(0.0f,0.0f,2.0f));
360        osg::Geode* background = new osg::Geode;
361        background->addDrawable(geometry);
362        front->addChild(background);
363       
364        osg::StateSet* stateset = geometry->getOrCreateStateSet();
365        stateset->setAttributeAndModes(new osg::PolygonOffset(2.0f,2.0f),osg::StateAttribute::ON);
366        stateset->setTextureAttributeAndModes(0,new osg::Texture2D(osgDB::readImageFile("lz.rgb")),osg::StateAttribute::ON);
367    }
368   
369    NodeList::iterator itr;
370    for(itr=nodes.begin();
371        itr!=nodes.end();
372        ++itr)
373    {
374        osg::MatrixTransform* mt = new osg::MatrixTransform;
375        mt->setMatrix(osg::Matrix::scale(scale*0.45f,scale*0.45f,scale*0.45f)*osg::Matrix::translate(pos));
376        mt->addChild(itr->get());
377        front->addChild(mt);
378
379        i++;
380        if ((i%nodes_across)==0)
381        {
382            leftMargin += down_delta;
383            pos = leftMargin;
384        }
385        else pos += across_delta;
386    }
387   
388   
389    for(itr=nodes.begin();
390        itr!=nodes.end();
391        ++itr)
392    {
393        sw->addChild(itr->get());
394    }
395
396    if (sw->getNumChildren()>0)
397    {
398        // select first child.
399        sw->setSingleChildOn(0);
400    }
401
402    return sw;
403}
404
405int main( int argc, char **argv )
406{
407
408    // use an ArgumentParser object to manage the program arguments.
409    osg::ArgumentParser arguments(&argc,argv);
410   
411    // set up the usage document, in case we need to print out how to use this program.
412    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates use node masks to create stereo images.");
413    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] image_file [image_file]");
414    arguments.getApplicationUsage()->addCommandLineOption("-d <float>","Time delay in sceonds between the display of successive image pairs when in auto advance mode.");
415    arguments.getApplicationUsage()->addCommandLineOption("-a","Enter auto advance of image pairs on start up.");
416    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
417   
418
419    // construct the viewer.
420    osgProducer::Viewer viewer(arguments);
421
422    // set up the value with sensible default event handlers.
423    //viewer.setUpViewer(osgProducer::Viewer::ESCAPE_SETS_DONE);
424    viewer.setUpViewer();
425
426    // register the handler to add keyboard and mosue handling.
427    SlideEventHandler* seh = new SlideEventHandler();
428    viewer.getEventHandlerList().push_front(seh);
429
430
431    // get details on keyboard and mouse bindings used by the viewer.
432    viewer.getUsage(*arguments.getApplicationUsage());
433
434    // read any time delay argument.
435    float timeDelayBetweenSlides = 5.0f;
436    while (arguments.read("-d",timeDelayBetweenSlides)) {}
437
438    bool autoSteppingActive = false;
439    while (arguments.read("-a")) autoSteppingActive = true;
440
441    // if user request help write it out to cout.
442    if (arguments.read("-h") || arguments.read("--help"))
443    {
444        arguments.getApplicationUsage()->write(std::cout);
445        return 1;
446    }
447
448    // any option left unread are converted into errors to write out later.
449    arguments.reportRemainingOptionsAsUnrecognized();
450
451    // report any errors if they have occured when parsing the program aguments.
452    if (arguments.errors())
453    {
454        arguments.writeErrorMessages(std::cout);
455        return 1;
456    }
457   
458    if (arguments.argc()<=1)
459    {
460        arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
461        return 1;
462    }
463
464    // extract the filenames from the arguments list.
465    FileList fileList;
466    for(int pos=1;pos<arguments.argc();++pos)
467    {
468        if (arguments.isString(pos)) fileList.push_back(arguments[pos]);
469    }
470
471    if (fileList.size()<2)
472    {
473        return 1;
474    }
475
476
477    // now the windows have been realized we switch off the cursor to prevent it
478    // distracting the people seeing the stereo images.
479    float fovy = 1.0f;
480    for( unsigned int i = 0; i < viewer.getCameraConfig()->getNumberOfCameras(); i++ )
481    {
482        Producer::Camera* cam = viewer.getCameraConfig()->getCamera(i);
483        Producer::RenderSurface* rs = cam->getRenderSurface();
484        rs->useCursor(false);
485        fovy = cam->getLensVerticalFov();
486    }
487
488    float radius = 1.0f;
489    float height = 2*radius*tan(fovy*0.5f);
490    float length = osg::PI*radius;  // half a cylinder.
491
492    // creat the scene from the file list.
493    osg::ref_ptr<osg::Switch> rootNode = createScene(fileList,height,length);
494   
495    if (!rootNode) return 0;
496
497
498    //osgDB::writeNodeFile(*rootNode,"test.osg");
499
500    // set the scene to render
501    viewer.setSceneData(rootNode.get());
502
503
504    // set up the SlideEventHandler.
505    seh->set(rootNode.get(),timeDelayBetweenSlides,autoSteppingActive);
506   
507
508    // create the windows and run the threads.
509    viewer.realize();
510   
511    osg::Matrix homePosition;
512    homePosition.makeLookAt(osg::Vec3(0.0f,0.0f,0.0f),osg::Vec3(0.0f,1.0f,0.0f),osg::Vec3(0.0f,0.0f,1.0f));
513       
514    while( !viewer.done() )
515    {
516        // wait for all cull and draw threads to complete.
517        viewer.sync();
518
519        // update the scene by traversing it with the the update visitor which will
520        // call all node update callbacks and animations.
521        viewer.update();
522         
523        //viewer.setView(homePosition);
524
525        // fire off the cull and draw traversals of the scene.
526        viewer.frame();
527       
528    }
529   
530    // wait for all cull and draw threads to complete before exit.
531    viewer.sync();
532   
533    return 0;
534}
Note: See TracBrowser for help on using the browser.