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