1 /* OpenSceneGraph example, osgphotoalbum.
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/Notify>
20 #include <osg/MatrixTransform>
21 #include <osg/Switch>
22 #include <osg/PolygonOffset>
23 #include <osg/CullFace>
24 
25 #include <osgUtil/Optimizer>
26 
27 #include <osgDB/FileNameUtils>
28 
29 #include <osgText/Text>
30 
31 #include <osgViewer/Viewer>
32 
33 #include "ImageReaderWriter.h"
34 
35 #include <iostream>
36 
37 using namespace osg;
38 
39 // now register with Registry to instantiate the above reader/writer,
40 // declaring in main so that the code to set up PagedLOD can get a handle
41 // to the ImageReaderWriter's
42 osgDB::RegisterReaderWriterProxy<ImageReaderWriter> g_ImageReaderWriter;
43 
44 class Album;
45 
46 class Page : public osg::Transform
47 {
48 public:
49 
50 
createPage(Album * album,unsigned int pageNo,const std::string & frontFileName,const std::string & backFileName,float width,float height)51     static Page* createPage(Album* album, unsigned int pageNo, const std::string& frontFileName, const std::string& backFileName, float width, float height)
52     {
53         osg::ref_ptr<Page> page = new Page(album, pageNo, frontFileName, backFileName, width, height);
54         if (page.valid()) return page.release();
55         else return 0;
56     }
57 
58     virtual void traverse(osg::NodeVisitor& nv);
59 
setRotation(float angle)60     void setRotation(float angle)
61     {
62         _rotation = angle;
63         _targetRotation = angle;
64         dirtyBound();
65     }
66 
getRotation() const67     float getRotation() const { return _rotation; }
68 
rotateTo(float angle,float timeToRotateBy)69     void rotateTo(float angle, float timeToRotateBy)
70     {
71         _targetRotation = angle;
72         _targetTime = timeToRotateBy;
73     }
74 
rotating() const75     bool rotating() const { return _targetRotation!=_rotation; }
76 
setPageVisible(bool frontVisible,bool backVisible)77     void setPageVisible(bool frontVisible,bool backVisible)
78     {
79         _switch->setValue(0,!frontVisible && !backVisible);
80         _switch->setValue(1,frontVisible);
81         _switch->setValue(2,backVisible);
82     }
83 
getSwitch()84     osg::Switch* getSwitch() { return _switch.get(); }
getSwitch() const85     const osg::Switch* getSwitch() const { return _switch.get(); }
86 
87 public:
88 
computeLocalToWorldMatrix(osg::Matrix & matrix,osg::NodeVisitor *) const89     virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor*) const
90     {
91         if (_referenceFrame==RELATIVE_RF)
92         {
93             matrix.preMult(getMatrix());
94         }
95         else // absolute
96         {
97             matrix = getMatrix();
98         }
99         return true;
100     }
101 
102     /** Get the transformation matrix which moves from world coords to local coords.*/
computeWorldToLocalMatrix(osg::Matrix & matrix,osg::NodeVisitor *) const103     virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,osg::NodeVisitor*) const
104     {
105         const osg::Matrix& inverse = getInverseMatrix();
106 
107         if (_referenceFrame==RELATIVE_RF)
108         {
109             matrix.postMult(inverse);
110         }
111         else // absolute
112         {
113             matrix = inverse;
114         }
115         return true;
116     }
117 
getMatrix() const118     osg::Matrix getMatrix() const { return _pageOffset*osg::Matrix::rotate(-_rotation,0.0f,0.0f,1.0f); }
getInverseMatrix() const119     osg::Matrix getInverseMatrix() const { return osg::Matrix::inverse(getMatrix()); }
120 
121 protected:
122 
123     Page(Album* album, unsigned int pageNo, const std::string& frontFileName, const std::string& backFileName, float width, float height);
124 
125     float       _rotation;
126     osg::Matrix _pageOffset;
127 
128     float       _targetRotation;
129     float       _targetTime;
130     float       _lastTimeTraverse;
131 
132     osg::ref_ptr<osg::Switch>     _switch;
133 
134 };
135 
136 
137 class Album : public osg::Referenced
138 {
139 public:
140 
141     Album(osg::ArgumentParser& ap, float width, float height);
142 
getScene()143     osg::Group* getScene() { return _group.get(); }
144 
getScene() const145     const osg::Group* getScene() const { return _group.get(); }
146 
147     osg::Matrix getPageOffset(unsigned int pageNo) const;
148 
nextPage(float timeToRotateBy)149     bool nextPage(float timeToRotateBy) { return gotoPage(_currentPageNo+1,timeToRotateBy); }
150 
previousPage(float timeToRotateBy)151     bool previousPage(float timeToRotateBy) { return _currentPageNo>=1?gotoPage(_currentPageNo-1,timeToRotateBy):false; }
152 
153     bool gotoPage(unsigned int pageNo, float timeToRotateBy);
154 
getBackgroundStateSet()155     osg::StateSet* getBackgroundStateSet() { return _backgroundStateSet.get(); }
156 
157     void setVisibility();
158 
159 protected:
160 
161     typedef std::vector< osg::ref_ptr<Page> > PageList;
162 
163     osg::ref_ptr<osg::Group>    _group;
164     PageList                    _pages;
165 
166     osg::ref_ptr<osg::StateSet> _backgroundStateSet;
167 
168     unsigned int                _currentPageNo;
169     float                       _radiusOfRings;
170     float                       _startAngleOfPages;
171     float                       _deltaAngleBetweenPages;
172 
173 };
174 
175 
176 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
177 
178 
Page(Album * album,unsigned int pageNo,const std::string & frontFileName,const std::string & backFileName,float width,float height)179 Page::Page(Album* album, unsigned int pageNo, const std::string& frontFileName, const std::string& backFileName, float width, float height)
180 {
181     // set up transform parts.
182     _rotation = 0;
183     _targetRotation = 0;
184     _targetTime = 0;
185     _lastTimeTraverse = 0;
186 
187     _pageOffset = album->getPageOffset(pageNo);
188 
189     setNumChildrenRequiringUpdateTraversal(1);
190 
191 
192     // set up subgraph
193     osgDB::ReaderWriter* readerWriter = osgDB::Registry::instance()->getReaderWriterForExtension("gdal");
194     if (!readerWriter)
195     {
196         std::cout<<"Error: GDAL plugin not available, cannot proceed with database creation"<<std::endl;
197     }
198 
199     _switch = new osg::Switch;
200 
201     ImageReaderWriter* rw = g_ImageReaderWriter.get();
202 
203 
204     // set up non visible page.
205     osg::Group* non_visible_page = new osg::Group;
206     _switch->addChild(non_visible_page);
207     {
208         osg::Geometry* geom = new osg::Geometry;
209         geom->setStateSet(album->getBackgroundStateSet());
210 
211         osg::Vec3Array* coords = new osg::Vec3Array(8);
212         (*coords)[0].set(0.0f,0.0f,0.0f);
213         (*coords)[1].set(0.0f,0.0f,height);
214         (*coords)[2].set(0.0f,0.0f,height);
215         (*coords)[3].set(width,0.0f,height);
216         (*coords)[4].set(width,0.0f,height);
217         (*coords)[5].set(width,0.0f,0.0f);
218         (*coords)[6].set(width,0.0f,0.0f);
219         (*coords)[7].set(0.0f,0.0f,0.0f);
220         geom->setVertexArray(coords);
221 
222 
223         osg::Vec3Array* normals = new osg::Vec3Array(8);
224         (*normals)[0].set(-1.0f,0.0f,0.0f);
225         (*normals)[1].set(-1.0f,0.0f,0.0f);
226         (*normals)[2].set(0.0f,0.0f,-1.0f);
227         (*normals)[3].set(0.0f,0.0f,-1.0f);
228         (*normals)[4].set(1.0f,0.0f,0.0f);
229         (*normals)[5].set(1.0f,0.0f,0.0f);
230         (*normals)[6].set(0.0f,0.0f,1.0f);
231         (*normals)[7].set(0.0f,0.0f,1.0f);
232         geom->setNormalArray(normals, osg::Array::BIND_PER_VERTEX);
233 
234         osg::Vec2Array* tcoords = new osg::Vec2Array(8);
235         (*tcoords)[0].set(0.0f,0.0f);
236         (*tcoords)[1].set(0.0f,1.0f);
237         (*tcoords)[2].set(0.0f,1.0f);
238         (*tcoords)[3].set(1.0f,1.0f);
239         (*tcoords)[4].set(1.0f,1.0f);
240         (*tcoords)[5].set(0.0f,1.0f);
241         (*tcoords)[6].set(0.0f,1.0f);
242         (*tcoords)[7].set(0.0f,0.0f);
243         geom->setTexCoordArray(0,tcoords);
244 
245         osg::Vec4Array* colours = new osg::Vec4Array(1);
246         (*colours)[0].set(1.0f,1.0f,1.0,1.0f);
247         geom->setColorArray(colours, osg::Array::BIND_OVERALL);
248 
249         geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,8));
250 
251         // set up the geode.
252         osg::Geode* geode = new osg::Geode;
253         geode->addDrawable(geom);
254 
255 
256         non_visible_page->addChild(geode);
257     }
258 
259 
260     // set up visible page.
261     osg::Group* front_page = new osg::Group;
262     _switch->addChild(front_page);
263 
264     {
265 
266         osg::Geometry* geom = new osg::Geometry;
267         geom->setStateSet(album->getBackgroundStateSet());
268 
269         osg::Vec3Array* coords = new osg::Vec3Array(4);
270         (*coords)[0].set(0.0f,0.0,height);
271         (*coords)[1].set(0.0f,0.0,0);
272         (*coords)[2].set(width,0.0,0);
273         (*coords)[3].set(width,0.0,height);
274         geom->setVertexArray(coords);
275 
276         osg::Vec3Array* normals = new osg::Vec3Array(1);
277         (*normals)[0].set(0.0f,-1.0f,0.0f);
278         geom->setNormalArray(normals, osg::Array::BIND_OVERALL);
279 
280         osg::Vec2Array* tcoords = new osg::Vec2Array(4);
281         (*tcoords)[0].set(0.0f,1.0f);
282         (*tcoords)[1].set(0.0f,0.0f);
283         (*tcoords)[2].set(1.0f,0.0f);
284         (*tcoords)[3].set(1.0f,1.0f);
285         geom->setTexCoordArray(0,tcoords);
286 
287         osg::Vec4Array* colours = new osg::Vec4Array(1);
288         (*colours)[0].set(1.0f,1.0f,1.0,1.0f);
289         geom->setColorArray(colours, osg::Array::BIND_OVERALL);
290 
291         geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));
292 
293         // set up the geode.
294         osg::Geode* geode = new osg::Geode;
295         geode->addDrawable(geom);
296 
297 
298         front_page->addChild(geode);
299     }
300 
301     if (!frontFileName.empty())
302     {
303         float cut_off_distance = 8.0f;
304         float max_visible_distance = 300.0f;
305 
306         osg::Vec3 center(width*0.5f,0.0f,height*0.5f);
307 
308         osgText::Text* text = new osgText::Text;
309         text->setFont("fonts/arial.ttf");
310         text->setPosition(center);
311         text->setCharacterSize(height/20.0f);
312         text->setAlignment(osgText::Text::CENTER_CENTER);
313         text->setAxisAlignment(osgText::Text::XZ_PLANE);
314         text->setColor(osg::Vec4(1.0f,1.0f,0.0f,1.0f));
315         text->setText(std::string("Loading ")+frontFileName);
316 
317         osg::Geode* geode = new osg::Geode;
318         geode->addDrawable(text);
319 
320         osg::PagedLOD* pagedlod = new osg::PagedLOD;
321         pagedlod->setCenter(center);
322         pagedlod->setRadius(1.6f);
323         pagedlod->setNumChildrenThatCannotBeExpired(2);
324 
325         pagedlod->setRange(0,max_visible_distance,1e7);
326         pagedlod->addChild(geode);
327 
328         pagedlod->setRange(1,cut_off_distance,max_visible_distance);
329         pagedlod->setFileName(1,rw->insertReference(frontFileName,256,width,height,false));
330 
331         pagedlod->setRange(2,0.0f,cut_off_distance);
332         pagedlod->setFileName(2,rw->insertReference(frontFileName,1024,width,height,false));
333 
334         front_page->addChild(pagedlod);
335     }
336 
337 
338     // set up back of page.
339     osg::Group* back_page = new osg::Group;
340     _switch->addChild(back_page);
341 
342     {
343 
344         osg::Geometry* geom = new osg::Geometry;
345         geom->setStateSet(album->getBackgroundStateSet());
346 
347         osg::Vec3Array* coords = new osg::Vec3Array(4);
348         (*coords)[0].set(width,0.0,height);
349         (*coords)[1].set(width,0.0,0);
350         (*coords)[2].set(0.0f,0.0,0);
351         (*coords)[3].set(0.0f,0.0,height);
352         geom->setVertexArray(coords);
353 
354         osg::Vec3Array* normals = new osg::Vec3Array(1);
355         (*normals)[0].set(0.0f,1.0f,0.0f);
356         geom->setNormalArray(normals, osg::Array::BIND_OVERALL);
357 
358         osg::Vec2Array* tcoords = new osg::Vec2Array(4);
359         (*tcoords)[0].set(1.0f,1.0f);
360         (*tcoords)[1].set(1.0f,0.0f);
361         (*tcoords)[2].set(0.0f,0.0f);
362         (*tcoords)[3].set(0.0f,1.0f);
363         geom->setTexCoordArray(0,tcoords);
364 
365         osg::Vec4Array* colours = new osg::Vec4Array(1);
366         (*colours)[0].set(1.0f,1.0f,1.0,1.0f);
367         geom->setColorArray(colours, osg::Array::BIND_OVERALL);
368 
369         geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));
370 
371         // set up the geode.
372         osg::Geode* geode = new osg::Geode;
373         geode->addDrawable(geom);
374 
375 
376         back_page->addChild(geode);
377     }
378 
379     if (!backFileName.empty())
380     {
381         float cut_off_distance = 8.0f;
382         float max_visible_distance = 300.0f;
383 
384         osg::Vec3 center(width*0.5f,0.0f,height*0.5f);
385 
386         osgText::Text* text = new osgText::Text;
387         text->setFont("fonts/arial.ttf");
388         text->setPosition(center);
389         text->setCharacterSize(height/20.0f);
390         text->setAlignment(osgText::Text::CENTER_CENTER);
391         text->setAxisAlignment(osgText::Text::REVERSED_XZ_PLANE);
392         text->setColor(osg::Vec4(1.0f,1.0f,0.0f,1.0f));
393         text->setText(std::string("Loading ")+backFileName);
394 
395         osg::Geode* geode = new osg::Geode;
396         geode->addDrawable(text);
397 
398         osg::PagedLOD* pagedlod = new osg::PagedLOD;
399         pagedlod->setCenter(center);
400         pagedlod->setRadius(1.6f);
401         pagedlod->setNumChildrenThatCannotBeExpired(2);
402 
403         pagedlod->setRange(0,max_visible_distance,1e7);
404         pagedlod->addChild(geode);
405 
406         pagedlod->setRange(1,cut_off_distance,max_visible_distance);
407         pagedlod->setFileName(1,rw->insertReference(backFileName,256,width,height,true));
408 
409         pagedlod->setRange(2,0.0f,cut_off_distance);
410         pagedlod->setFileName(2,rw->insertReference(backFileName,1024,width,height,true));
411 
412         back_page->addChild(pagedlod);
413     }
414 
415     addChild(_switch.get());
416 }
417 
traverse(osg::NodeVisitor & nv)418 void Page::traverse(osg::NodeVisitor& nv)
419 {
420     // if app traversal update the frame count.
421     if (nv.getVisitorType()==osg::NodeVisitor::UPDATE_VISITOR)
422     {
423         const osg::FrameStamp* framestamp = nv.getFrameStamp();
424         if (framestamp)
425         {
426             double t = framestamp->getSimulationTime();
427 
428             if (_rotation!=_targetRotation)
429             {
430                 if (t>=_targetTime) _rotation = _targetRotation;
431                 else _rotation += (_targetRotation-_rotation)*(t-_lastTimeTraverse)/(_targetTime-_lastTimeTraverse);
432 
433                 dirtyBound();
434             }
435 
436             _lastTimeTraverse = t;
437 
438         }
439     }
440     Transform::traverse(nv);
441 }
442 
443 
444 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
445 
Album(osg::ArgumentParser & arguments,float width,float height)446 Album::Album(osg::ArgumentParser& arguments, float width, float height)
447 {
448 
449 
450     typedef std::vector<std::string> FileList;
451     FileList fileList;
452 
453     for(int pos=1;pos<arguments.argc();++pos)
454     {
455         if (arguments.isString(pos))
456         {
457             std::string filename(arguments[pos]);
458             if (osgDB::getLowerCaseFileExtension(filename)=="album")
459             {
460                 PhotoArchive* photoArchive = PhotoArchive::open(filename);
461                 if (photoArchive)
462                 {
463                     g_ImageReaderWriter.get()->addPhotoArchive(photoArchive);
464                     photoArchive->getImageFileNameList(fileList);
465                 }
466 
467             }
468             else
469             {
470                 fileList.push_back(arguments[pos]);
471             }
472         }
473     }
474 
475     _radiusOfRings = 0.02;
476     _startAngleOfPages = 0.0f;
477     _deltaAngleBetweenPages = osg::PI/(float)fileList.size();
478 
479     _group = new osg::Group;
480     _group->getOrCreateStateSet()->setAttributeAndModes(new osg::CullFace,osg::StateAttribute::ON);
481 
482     _backgroundStateSet = new osg::StateSet;
483     _backgroundStateSet->setAttributeAndModes(new osg::PolygonOffset(1.0f,1.0f),osg::StateAttribute::ON);
484 
485     // load the images.
486     unsigned int i;
487     for(i=0;i<fileList.size();i+=2)
488     {
489         Page* page = i+1<fileList.size()?
490                      Page::createPage(this,_pages.size(),fileList[i],fileList[i+1], width, height):
491                      Page::createPage(this,_pages.size(),fileList[i],"", width, height);
492         if (page)
493         {
494             _pages.push_back(page);
495             _group->addChild(page);
496         }
497     }
498 
499     setVisibility();
500 
501 }
502 
getPageOffset(unsigned int pageNo) const503 osg::Matrix Album::getPageOffset(unsigned int pageNo) const
504 {
505     float angleForPage = _startAngleOfPages+_deltaAngleBetweenPages*(float)pageNo;
506     osg::Vec3 delta(_radiusOfRings*sinf(angleForPage),-_radiusOfRings*cosf(angleForPage),0.0f);
507     return osg::Matrix::translate(delta);
508 }
509 
gotoPage(unsigned int pageNo,float timeToRotateBy)510 bool Album::gotoPage(unsigned int pageNo, float timeToRotateBy)
511 {
512     if (pageNo>=_pages.size()) return false;
513 
514     if (pageNo>_currentPageNo)
515     {
516         for(unsigned int i=_currentPageNo;i<pageNo;++i)
517         {
518             _pages[i]->rotateTo(osg::PI,timeToRotateBy);
519         }
520         _currentPageNo = pageNo;
521 
522         return true;
523     }
524     else if (pageNo<_currentPageNo)
525     {
526         for(unsigned int i=pageNo;i<_currentPageNo;++i)
527         {
528             _pages[i]->rotateTo(0,timeToRotateBy);
529         }
530         _currentPageNo = pageNo;
531 
532         return true;
533     }
534 
535     return false;
536 }
537 
setVisibility()538 void Album::setVisibility()
539 {
540     for(unsigned int i=0;i<_pages.size();++i)
541     {
542         bool front_visible = _pages[i]->rotating() ||
543                              (i>0?_pages[i-1]->rotating():false) ||
544                              i==_currentPageNo ||
545                              i==0;
546 
547         bool back_visible = _pages[i]->rotating() ||
548                             ((i+1)<_pages.size()?_pages[i+1]->rotating():false) ||
549                             i==_currentPageNo-1 ||
550                             i==_pages.size()-1;
551 
552         _pages[i]->setPageVisible(front_visible,back_visible);
553     }
554 
555 }
556 
557 
558 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
559 
560 
561 class SlideEventHandler : public osgGA::GUIEventHandler
562 {
563 public:
564 
565     SlideEventHandler();
566 
567     META_Object(osgStereImageApp,SlideEventHandler);
568 
569     void set(Album* album, float timePerSlide, bool autoSteppingActive);
570 
571     virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&);
572 
573     virtual void getUsage(osg::ApplicationUsage& usage) const;
574 
575 protected:
576 
~SlideEventHandler()577     ~SlideEventHandler() {}
SlideEventHandler(const SlideEventHandler &,const osg::CopyOp &)578     SlideEventHandler(const SlideEventHandler&,const osg::CopyOp&) {}
579 
580     osg::ref_ptr<Album>         _album;
581     bool                        _firstTraversal;
582     double                      _previousTime;
583     double                      _timePerSlide;
584     bool                        _autoSteppingActive;
585 };
586 
SlideEventHandler()587 SlideEventHandler::SlideEventHandler():
588     _album(0),
589     _firstTraversal(true),
590     _previousTime(-1.0f),
591     _timePerSlide(5.0),
592     _autoSteppingActive(false)
593 {
594 }
595 
set(Album * album,float timePerSlide,bool autoSteppingActive)596 void SlideEventHandler::set(Album* album, float timePerSlide, bool autoSteppingActive)
597 {
598     _album = album;
599 
600     _timePerSlide = timePerSlide;
601     _autoSteppingActive = autoSteppingActive;
602 
603 }
604 
handle(const osgGA::GUIEventAdapter & ea,osgGA::GUIActionAdapter &)605 bool SlideEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&)
606 {
607     switch(ea.getEventType())
608     {
609         case(osgGA::GUIEventAdapter::KEYDOWN):
610         {
611             if (ea.getKey()=='a')
612             {
613                 _autoSteppingActive = !_autoSteppingActive;
614                 _previousTime = ea.getTime();
615                 return true;
616             }
617             else if (ea.getKey()=='n')
618             {
619                 _album->nextPage(ea.getTime()+1.0f);
620                 return true;
621             }
622             else if (ea.getKey()=='p')
623             {
624                 _album->previousPage(ea.getTime()+1.0f);
625                 return true;
626             }
627             return false;
628         }
629         case(osgGA::GUIEventAdapter::FRAME):
630         {
631             if (_autoSteppingActive)
632             {
633                 if (_firstTraversal)
634                 {
635                     _firstTraversal = false;
636                     _previousTime = ea.getTime();
637                 }
638                 else if (ea.getTime()-_previousTime>_timePerSlide)
639                 {
640                     _previousTime = ea.getTime();
641 
642                     _album->nextPage(ea.getTime()+1.0f);
643                 }
644             }
645 
646             _album->setVisibility();
647             return true;
648 
649         }
650 
651         default:
652             return false;
653     }
654 }
655 
getUsage(osg::ApplicationUsage & usage) const656 void SlideEventHandler::getUsage(osg::ApplicationUsage& usage) const
657 {
658     usage.addKeyboardMouseBinding("Space","Reset the image position to center");
659     usage.addKeyboardMouseBinding("a","Toggle on/off the automatic advancement for image to image");
660     usage.addKeyboardMouseBinding("n","Advance to next image");
661     usage.addKeyboardMouseBinding("p","Move to previous image");
662 }
663 
main(int argc,char ** argv)664 int main( int argc, char **argv )
665 {
666 
667     // use an ArgumentParser object to manage the program arguments.
668     osg::ArgumentParser arguments(&argc,argv);
669 
670     // set up the usage document, in case we need to print out how to use this program.
671     arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates use node masks to create stereo images.");
672     arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] image_file [image_file]");
673     arguments.getApplicationUsage()->addCommandLineOption("-d <float>","Time delay in seconds between the display of successive image pairs when in auto advance mode.");
674     arguments.getApplicationUsage()->addCommandLineOption("-a","Enter auto advance of image pairs on start up.");
675     arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
676     arguments.getApplicationUsage()->addCommandLineOption("--create <filename>","Create an photo archive of specified files");
677 
678 
679     // construct the viewer.
680     osgViewer::Viewer viewer(arguments);
681 
682     viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded);
683 
684     // register the handler to add keyboard and mouse handling.
685     SlideEventHandler* seh = new SlideEventHandler();
686     viewer.addEventHandler(seh);
687 
688     // read any time delay argument.
689     float timeDelayBetweenSlides = 5.0f;
690     while (arguments.read("-d",timeDelayBetweenSlides)) {}
691 
692     bool autoSteppingActive = false;
693     while (arguments.read("-a")) autoSteppingActive = true;
694 
695     // if user request help write it out to cout.
696     if (arguments.read("-h") || arguments.read("--help"))
697     {
698         arguments.getApplicationUsage()->write(std::cout);
699         return 1;
700     }
701 
702     std::string archiveName;
703     while (arguments.read("--create",archiveName)) {}
704 
705     // any option left unread are converted into errors to write out later.
706     arguments.reportRemainingOptionsAsUnrecognized();
707 
708     // report any errors if they have occurred when parsing the program arguments.
709     if (arguments.errors())
710     {
711         arguments.writeErrorMessages(std::cout);
712         return 1;
713     }
714 
715     if (arguments.argc()<=1)
716     {
717         arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
718         return 1;
719     }
720 
721 
722     if (!archiveName.empty())
723     {
724         // archive name set to create
725         PhotoArchive::FileNameList fileNameList;
726         for(int i=1;i<arguments.argc();++i)
727         {
728             if (arguments.isString(i)) fileNameList.push_back(std::string(arguments[i]));
729         }
730 
731         PhotoArchive::buildArchive(archiveName,fileNameList);
732 
733         return 0;
734     }
735 
736 
737     // now the windows have been realized we switch off the cursor to prevent it
738     // distracting the people seeing the stereo images.
739     double fovy, aspectRatio, zNear, zFar;
740     viewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspectRatio, zNear, zFar);
741 
742     fovy = osg::DegreesToRadians(fovy);
743     double fovx = atan(tan(fovy*0.5)*aspectRatio)*2.0;
744 
745     float radius = 1.0f;
746     float width = 2*radius*tan(fovx*0.5f);
747     float height = 2*radius*tan(fovy*0.5f);
748 
749     osg::ref_ptr<Album> album = new Album(arguments,width,height);
750 
751     // create the scene from the file list.
752     osg::ref_ptr<osg::Group> rootNode = album->getScene();
753 
754     if (!rootNode) return 0;
755 
756 
757     //osgDB::writeNodeFile(*rootNode,"test.osgt");
758 
759     // set the scene to render
760     viewer.setSceneData(album->getScene());
761 
762     // set up the SlideEventHandler.
763     seh->set(album.get(),timeDelayBetweenSlides,autoSteppingActive);
764 
765     viewer.realize();
766 
767     // switch off the cursor
768     osgViewer::Viewer::Windows windows;
769     viewer.getWindows(windows);
770     for(osgViewer::Viewer::Windows::iterator itr = windows.begin();
771         itr != windows.end();
772         ++itr)
773     {
774         (*itr)->useCursor(false);
775     }
776 
777 
778     return viewer.run();
779 }
780 
781