Show
Ignore:
Timestamp:
12/15/03 17:40:26 (11 years ago)
Author:
robert
Message:

Added gemetry of photo album and page turning animation.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • OpenSceneGraph/trunk/examples/osgphotoalbum/osgphotoalbum.cpp

    r2521 r2539  
    4343                _resolutionX(256), 
    4444                _resolutionY(256), 
    45                 _center(0.0f,0.0f,0.0f), 
     45                _center(0.625f,0.0f,0.0f), 
    4646                _maximumWidth(1.25f,0.0f,0.0f), 
    4747                _maximumHeight(0.0f,0.0f,1.0f), 
     
    4949                _numPointsUp(10) {} 
    5050 
    51             DataReference(const std::string& fileName, unsigned int res): 
     51            DataReference(const std::string& fileName, unsigned int res, float width, float height): 
    5252                _fileName(fileName), 
    5353                _resolutionX(res), 
    5454                _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), 
     55                _center(width*0.5f,0.0f,height*0.5f), 
     56                _maximumWidth(width,0.0f,0.0f), 
     57                _maximumHeight(0.0f,0.0f,height), 
    5858                _numPointsAcross(10),  
    5959                _numPointsUp(10) {} 
     
    8282        DataReferenceMap _dataReferences; 
    8383         
    84         std::string insertReference(const std::string& fileName, unsigned int res) 
     84        std::string insertReference(const std::string& fileName, unsigned int res, float width, float height) 
    8585        { 
    8686            std::stringstream ostr; 
     
    8888 
    8989            std::string myReference = ostr.str(); 
    90             _dataReferences[myReference] = DataReference(fileName,res); 
     90            _dataReferences[myReference] = DataReference(fileName,res,width,height); 
    9191            return myReference; 
    9292        } 
     
    123123                float t = options.valid()?options->_sourcePixelWindow.windowHeight:1.0f; 
    124124             
    125                 osg::Geode* geode = osg::createGeodeForImage(image,s,t); 
     125                float photoWidth = 0.0f; 
     126                float photoHeight = 0.0f; 
     127                float maxWidth = dr._maximumWidth.length(); 
     128                float maxHeight = dr._maximumHeight.length(); 
     129                 
     130                 
     131                if ((s/t)>(maxWidth/maxHeight)) 
     132                { 
     133                    // photo wider than tall relative to the required pictures size. 
     134                    // so need to clamp the width to the maximum width and then 
     135                    // set the height to keep the original photo aspect ratio. 
     136                     
     137                    photoWidth = maxWidth; 
     138                    photoHeight = photoWidth*(t/s); 
     139                } 
     140                else 
     141                { 
     142                    // photo tall than wide relative to the required pictures size. 
     143                    // so need to clamp the height to the maximum height and then 
     144                    // set the width to keep the original photo aspect ratio. 
     145                     
     146                    photoHeight = maxHeight; 
     147                    photoWidth = photoHeight*(s/t); 
     148                } 
     149                 
     150                osg::Vec3 halfWidthVector(dr._maximumWidth*(photoWidth*0.5f/maxWidth)); 
     151                osg::Vec3 halfHeightVector(dr._maximumHeight*(photoHeight*0.5f/maxHeight)); 
     152 
     153 
     154                // set up the texture. 
     155                osg::Texture2D* texture = new osg::Texture2D; 
     156                texture->setImage(image); 
     157                texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR); 
     158                texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR); 
     159 
     160                // set up the drawstate. 
     161                osg::StateSet* dstate = new osg::StateSet; 
     162                dstate->setMode(GL_LIGHTING,osg::StateAttribute::OFF); 
     163                dstate->setTextureAttributeAndModes(0, texture,osg::StateAttribute::ON); 
     164 
     165                // set up the geoset. 
     166                osg::Geometry* geom = new osg::Geometry; 
     167                geom->setStateSet(dstate); 
     168 
     169                osg::Vec3Array* coords = new osg::Vec3Array(4); 
     170                (*coords)[0] = dr._center - halfWidthVector + halfHeightVector; 
     171                (*coords)[1] = dr._center - halfWidthVector - halfHeightVector; 
     172                (*coords)[2] = dr._center + halfWidthVector - halfHeightVector; 
     173                (*coords)[3] = dr._center + halfWidthVector + halfHeightVector; 
     174                geom->setVertexArray(coords); 
     175 
     176                osg::Vec2Array* tcoords = new osg::Vec2Array(4); 
     177                (*tcoords)[0].set(0.0f,1.0f); 
     178                (*tcoords)[1].set(0.0f,0.0f); 
     179                (*tcoords)[2].set(1.0f,0.0f); 
     180                (*tcoords)[3].set(1.0f,1.0f); 
     181                geom->setTexCoordArray(0,tcoords); 
     182 
     183                osg::Vec4Array* colours = new osg::Vec4Array(1); 
     184                (*colours)[0].set(1.0f,1.0f,1.0,1.0f); 
     185                geom->setColorArray(colours); 
     186                geom->setColorBinding(osg::Geometry::BIND_OVERALL); 
     187 
     188                geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4)); 
     189 
     190                // set up the geode. 
     191                osg::Geode* geode = new osg::Geode; 
     192                geode->addDrawable(geom); 
     193                 
    126194                return geode; 
    127195             
     
    142210osgDB::RegisterReaderWriterProxy<ImageReaderWriter> g_ImageReaderWriter; 
    143211 
    144  
    145  
    146 typedef std::vector<std::string> FileList; 
    147  
    148 class SlideEventHandler : public osgGA::GUIEventHandler, public osg::NodeCallback 
     212class Album; 
     213 
     214class Page : public osg::Transform 
    149215{ 
    150216public: 
    151217 
     218 
     219    static Page* createPage(Album* album, unsigned int pageNo, const std::string& filename, float width, float height) 
     220    { 
     221        osg::ref_ptr<Page> page = new Page(album, pageNo, filename, width, height); 
     222        if (page.valid()) return page.release(); 
     223        else return 0; 
     224    } 
     225     
     226    virtual void traverse(osg::NodeVisitor& nv); 
     227 
     228    void setRotation(float angle) 
     229    { 
     230        _rotation = angle;  
     231        _targetRotation = angle;  
     232        dirtyBound(); 
     233    } 
     234 
     235    float getRotation() const { return _rotation; } 
     236 
     237    void rotateTo(float angle, float timeToRotateBy) 
     238    { 
     239        _targetRotation = angle;  
     240        _targetTime = timeToRotateBy; 
     241    } 
     242     
     243    bool rotating() const { return _targetRotation!=_rotation; } 
     244 
     245    void setPageVisible(bool visible) { _switch->setSingleChildOn(visible?1:0); } 
     246 
     247    osg::Switch* getSwitch() { return _switch.get(); } 
     248    const osg::Switch* getSwitch() const { return _switch.get(); } 
     249 
     250public: 
     251 
     252    virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor*) const  
     253    { 
     254        if (_referenceFrame==RELATIVE_TO_PARENTS) 
     255        { 
     256            matrix.preMult(getMatrix()); 
     257        } 
     258        else // absolute 
     259        { 
     260            matrix = getMatrix(); 
     261        } 
     262        return true; 
     263    } 
     264 
     265    /** Get the transformation matrix which moves from world coords to local coords.*/ 
     266    virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,osg::NodeVisitor*) const 
     267    { 
     268        const osg::Matrix& inverse = getInverseMatrix(); 
     269 
     270        if (_referenceFrame==RELATIVE_TO_PARENTS) 
     271        { 
     272            matrix.postMult(inverse); 
     273        } 
     274        else // absolute 
     275        { 
     276            matrix = inverse; 
     277        } 
     278        return true; 
     279    } 
     280 
     281    osg::Matrix getMatrix() const { return _pageOffset*osg::Matrix::rotate(-_rotation,0.0f,0.0f,1.0f); } 
     282    osg::Matrix getInverseMatrix() const { return osg::Matrix::inverse(getMatrix()); } 
     283 
     284protected: 
     285     
     286    Page(Album* album, unsigned int pageNo, const std::string& filename, float width, float height); 
     287 
     288    float       _rotation; 
     289    osg::Matrix _pageOffset; 
     290 
     291    float       _targetRotation; 
     292    float       _targetTime; 
     293    float       _lastTimeTraverse; 
     294 
     295    osg::ref_ptr<osg::Switch>     _switch; 
     296 
     297}; 
     298 
     299 
     300class Album : public osg::Referenced 
     301{ 
     302public: 
     303 
     304    Album(osg::ArgumentParser& ap, float width, float height); 
     305 
     306    osg::Group* getScene() { return _group.get(); } 
     307     
     308    const osg::Group* getScene() const { return _group.get(); } 
     309 
     310    osg::Matrix getPageOffset(unsigned int pageNo) const; 
     311     
     312    bool nextPage(float timeToRotateBy) { return gotoPage(_currentPageNo+1,timeToRotateBy); } 
     313 
     314    bool previousPage(float timeToRotateBy) { return _currentPageNo>=1?gotoPage(_currentPageNo-1,timeToRotateBy):false; } 
     315     
     316    bool gotoPage(unsigned int pageNo, float timeToRotateBy); 
     317     
     318    osg::StateSet* getBackgroundStateSet() { return _backgroundStateSet.get(); } 
     319     
     320    void setVisibility(); 
     321 
     322protected: 
     323 
     324    typedef std::vector< osg::ref_ptr<Page> > PageList; 
     325 
     326    osg::ref_ptr<osg::Group>    _group; 
     327    PageList                    _pages; 
     328     
     329    osg::ref_ptr<osg::StateSet> _backgroundStateSet; 
     330     
     331    unsigned int                _currentPageNo; 
     332    float                       _radiusOfRings; 
     333    float                       _startAngleOfPages; 
     334    float                       _deltaAngleBetweenPages;    
     335 
     336}; 
     337 
     338 
     339//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
     340 
     341 
     342Page::Page(Album* album, unsigned int pageNo, const std::string& filename, float width, float height) 
     343{ 
     344    // set up transform parts. 
     345    _rotation = 0; 
     346    _targetRotation = 0; 
     347    _targetTime = 0; 
     348    _lastTimeTraverse = 0; 
     349     
     350    _pageOffset = album->getPageOffset(pageNo); 
     351     
     352    setNumChildrenRequiringUpdateTraversal(1); 
     353     
     354     
     355    // set up subgraph 
     356    osgDB::ReaderWriter* readerWriter = osgDB::Registry::instance()->getReaderWriterForExtension("gdal"); 
     357    if (!readerWriter) 
     358    { 
     359        std::cout<<"Error: GDAL plugin not available, cannot preceed with database creation"<<std::endl; 
     360    } 
     361 
     362    _switch = new osg::Switch; 
     363 
     364    ImageReaderWriter* rw = g_ImageReaderWriter.get(); 
     365 
     366     
     367    // set up non visible page. 
     368    osg::Group* non_visible_page = new osg::Group; 
     369    _switch->addChild(non_visible_page); 
     370    { 
     371        // just an empty group for the time being... will need to create geometry soon. 
     372        osg::Geometry* geom = new osg::Geometry; 
     373        geom->setStateSet(album->getBackgroundStateSet()); 
     374 
     375        osg::Vec3Array* coords = new osg::Vec3Array(4); 
     376        (*coords)[0].set(0.0f,0.0,height); 
     377        (*coords)[1].set(0.0f,0.0,0); 
     378        (*coords)[2].set(width,0.0,0); 
     379        (*coords)[3].set(width,0.0,height); 
     380        geom->setVertexArray(coords); 
     381 
     382        osg::Vec3Array* normals = new osg::Vec3Array(1); 
     383        (*normals)[0].set(0.0f,-1.0f,0.0f); 
     384        geom->setNormalArray(normals); 
     385        geom->setNormalBinding(osg::Geometry::BIND_OVERALL); 
     386 
     387        osg::Vec2Array* tcoords = new osg::Vec2Array(4); 
     388        (*tcoords)[0].set(0.0f,1.0f); 
     389        (*tcoords)[1].set(0.0f,0.0f); 
     390        (*tcoords)[2].set(1.0f,0.0f); 
     391        (*tcoords)[3].set(1.0f,1.0f); 
     392        geom->setTexCoordArray(0,tcoords); 
     393 
     394        osg::Vec4Array* colours = new osg::Vec4Array(1); 
     395        (*colours)[0].set(1.0f,1.0f,1.0,1.0f); 
     396        geom->setColorArray(colours); 
     397        geom->setColorBinding(osg::Geometry::BIND_OVERALL); 
     398 
     399        geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP,0,4)); 
     400 
     401        // set up the geode. 
     402        osg::Geode* geode = new osg::Geode; 
     403        geode->addDrawable(geom); 
     404         
     405     
     406        non_visible_page->addChild(geode); 
     407    } 
     408 
     409 
     410    // set up visible page. 
     411    osg::Group* visible_page = new osg::Group; 
     412    _switch->addChild(visible_page); 
     413 
     414    { 
     415 
     416         
     417        osg::Geometry* geom = new osg::Geometry; 
     418        geom->setStateSet(album->getBackgroundStateSet()); 
     419 
     420        osg::Vec3Array* coords = new osg::Vec3Array(4); 
     421        (*coords)[0].set(0.0f,0.0,height); 
     422        (*coords)[1].set(0.0f,0.0,0); 
     423        (*coords)[2].set(width,0.0,0); 
     424        (*coords)[3].set(width,0.0,height); 
     425        geom->setVertexArray(coords); 
     426 
     427        osg::Vec3Array* normals = new osg::Vec3Array(1); 
     428        (*normals)[0].set(0.0f,-1.0f,0.0f); 
     429        geom->setNormalArray(normals); 
     430        geom->setNormalBinding(osg::Geometry::BIND_OVERALL); 
     431 
     432        osg::Vec2Array* tcoords = new osg::Vec2Array(4); 
     433        (*tcoords)[0].set(0.0f,1.0f); 
     434        (*tcoords)[1].set(0.0f,0.0f); 
     435        (*tcoords)[2].set(1.0f,0.0f); 
     436        (*tcoords)[3].set(1.0f,1.0f); 
     437        geom->setTexCoordArray(0,tcoords); 
     438 
     439        osg::Vec4Array* colours = new osg::Vec4Array(1); 
     440        (*colours)[0].set(1.0f,1.0f,1.0,1.0f); 
     441        geom->setColorArray(colours); 
     442        geom->setColorBinding(osg::Geometry::BIND_OVERALL); 
     443 
     444        geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4)); 
     445 
     446        // set up the geode. 
     447        osg::Geode* geode = new osg::Geode; 
     448        geode->addDrawable(geom); 
     449         
     450     
     451        visible_page->addChild(geode); 
     452    } 
     453 
     454    { 
     455        float cut_off_distance = 8.0f; 
     456        float max_visible_distance = 300.0f; 
     457         
     458        osg::Vec3 center(width*0.5f,0.0f,height*0.5f); 
     459 
     460        osgText::Text* text = new osgText::Text; 
     461        text->setFont("fonts/arial.ttf"); 
     462        text->setPosition(center); 
     463        text->setCharacterSize(height/20.0f); 
     464        text->setAlignment(osgText::Text::CENTER_CENTER); 
     465        text->setAxisAlignment(osgText::Text::XZ_PLANE); 
     466        text->setColor(osg::Vec4(1.0f,1.0f,0.0f,1.0f)); 
     467        text->setText(std::string("Loading ")+filename); 
     468 
     469        osg::Geode* geode = new osg::Geode; 
     470        geode->addDrawable(text); 
     471         
     472        osg::PagedLOD* pagedlod = new osg::PagedLOD; 
     473        pagedlod->setCenter(center); 
     474        pagedlod->setRadius(1.6f); 
     475        pagedlod->setNumChildrenThatCannotBeExpired(2); 
     476         
     477        pagedlod->setRange(0,max_visible_distance,1e7); 
     478        pagedlod->addChild(geode); 
     479         
     480        pagedlod->setRange(1,cut_off_distance,max_visible_distance); 
     481        pagedlod->setFileName(1,rw->insertReference(filename,256,width,height)); 
     482 
     483        pagedlod->setRange(2,0.0f,cut_off_distance); 
     484        pagedlod->setFileName(2,rw->insertReference(filename,1024,width,height)); 
     485 
     486        visible_page->addChild(pagedlod); 
     487    } 
     488     
     489    addChild(_switch.get()); 
     490} 
     491 
     492void Page::traverse(osg::NodeVisitor& nv) 
     493{ 
     494    // if app traversal update the frame count. 
     495    if (nv.getVisitorType()==osg::NodeVisitor::UPDATE_VISITOR) 
     496    { 
     497        const osg::FrameStamp* framestamp = nv.getFrameStamp(); 
     498        if (framestamp) 
     499        { 
     500            double t = framestamp->getReferenceTime(); 
     501             
     502            if (_rotation!=_targetRotation) 
     503            { 
     504                if (t>=_targetTime) _rotation = _targetRotation; 
     505                else _rotation += (_targetRotation-_rotation)*(t-_lastTimeTraverse)/(_targetTime-_lastTimeTraverse); 
     506                 
     507                dirtyBound(); 
     508            } 
     509             
     510            _lastTimeTraverse = t; 
     511 
     512        } 
     513    } 
     514    Transform::traverse(nv); 
     515} 
     516 
     517 
     518//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
     519 
     520Album::Album(osg::ArgumentParser& arguments, float width, float height) 
     521{ 
     522 
     523 
     524    typedef std::vector<std::string> FileList; 
     525    FileList fileList; 
     526 
     527    for(int pos=1;pos<arguments.argc();++pos) 
     528    { 
     529        if (arguments.isString(pos)) fileList.push_back(arguments[pos]); 
     530    } 
     531     
     532    _radiusOfRings = 0.02; 
     533    _startAngleOfPages = 0.0f; 
     534    _deltaAngleBetweenPages = osg::PI/(float)fileList.size(); 
     535     
     536    _group = new osg::Group; 
     537     
     538    _backgroundStateSet = new osg::StateSet; 
     539    _backgroundStateSet->setAttributeAndModes(new osg::PolygonOffset(1.0f,1.0f),osg::StateAttribute::ON); 
     540     
     541    // load the images. 
     542    unsigned int i; 
     543    for(i=0;i<fileList.size();++i) 
     544    { 
     545        Page* page = Page::createPage(this,_pages.size(),fileList[i], width, height); 
     546        if (page) 
     547        { 
     548            _pages.push_back(page); 
     549            _group->addChild(page); 
     550        } 
     551    } 
     552     
     553    setVisibility(); 
     554 
     555} 
     556 
     557osg::Matrix Album::getPageOffset(unsigned int pageNo) const 
     558{ 
     559    float angleForPage = _startAngleOfPages+_deltaAngleBetweenPages*(float)pageNo; 
     560    osg::Vec3 delta(_radiusOfRings*sinf(angleForPage),-_radiusOfRings*cosf(angleForPage),0.0f); 
     561    return osg::Matrix::translate(delta); 
     562} 
     563 
     564bool Album::gotoPage(unsigned int pageNo, float timeToRotateBy) 
     565{ 
     566    if (pageNo>=_pages.size()) return false; 
     567 
     568    if (pageNo>_currentPageNo) 
     569    { 
     570        for(unsigned int i=_currentPageNo;i<pageNo;++i) 
     571        { 
     572            _pages[i]->rotateTo(osg::PI,timeToRotateBy); 
     573        } 
     574        _pages[pageNo]->setPageVisible(true); 
     575        _currentPageNo = pageNo; 
     576         
     577        return true; 
     578    } 
     579    else if (pageNo<_currentPageNo) 
     580    { 
     581        for(unsigned int i=pageNo;i<_currentPageNo;++i) 
     582        { 
     583            _pages[i]->rotateTo(0,timeToRotateBy); 
     584        } 
     585        _pages[pageNo]->setPageVisible(true); 
     586        _currentPageNo = pageNo; 
     587         
     588        return true; 
     589    } 
     590     
     591    return false; 
     592} 
     593 
     594void Album::setVisibility() 
     595{ 
     596    for(unsigned int i=0;i<_pages.size();++i) 
     597    { 
     598        _pages[i]->setPageVisible(_pages[i]->rotating()); 
     599    } 
     600     
     601    //_pages[0]->setPageVisible(true); 
     602    //if (_currentPageNo>=1) _pages[_currentPageNo-1]->setPageVisible(true); 
     603    _pages[_currentPageNo]->setPageVisible(true); 
     604    //if (_currentPageNo<_pages.size()-1) _pages[_currentPageNo+1]->setPageVisible(true); 
     605    //_pages[_pages.size()-1]->setPageVisible(true); 
     606} 
     607 
     608 
     609//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
     610 
     611 
     612class SlideEventHandler : public osgGA::GUIEventHandler 
     613{ 
     614public: 
     615 
    152616    SlideEventHandler(); 
    153617     
    154618    META_Object(osgStereImageApp,SlideEventHandler); 
    155619 
    156     void set(osg::Switch* sw, float timePerSlide, bool autoSteppingActive); 
     620    void set(Album* album, float timePerSlide, bool autoSteppingActive); 
    157621 
    158622    virtual void accept(osgGA::GUIEventHandlerVisitor& v) { v.visit(*this); } 
     
    161625     
    162626    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(); 
    169627 
    170628protected: 
     
    173631    SlideEventHandler(const SlideEventHandler&,const osg::CopyOp&) {} 
    174632 
    175     osg::ref_ptr<osg::Switch>   _switch; 
     633    osg::ref_ptr<Album>         _album; 
    176634    bool                        _firstTraversal; 
    177     unsigned int                _activeSlide; 
    178635    double                      _previousTime; 
    179636    double                      _timePerSlide; 
     
    182639 
    183640SlideEventHandler::SlideEventHandler(): 
    184     _switch(0), 
     641    _album(0), 
    185642    _firstTraversal(true), 
    186     _activeSlide(0), 
    187643    _previousTime(-1.0f), 
    188644    _timePerSlide(5.0), 
     
    191647} 
    192648 
    193 void SlideEventHandler::set(osg::Switch* sw, float timePerSlide, bool autoSteppingActive) 
    194 { 
    195     _switch = sw; 
    196     _switch->setUpdateCallback(this); 
     649void SlideEventHandler::set(Album* album, float timePerSlide, bool autoSteppingActive) 
     650{ 
     651    _album = album; 
    197652 
    198653    _timePerSlide = timePerSlide; 
     
    215670            else if (ea.getKey()=='n') 
    216671            { 
    217                 nextSlide(); 
     672                _album->nextPage(ea.time()+1.0f); 
    218673                return true; 
    219674            } 
    220675            else if (ea.getKey()=='p') 
    221676            { 
    222                 previousSlide(); 
     677                _album->previousPage(ea.time()+1.0f); 
    223678                return true; 
    224679            } 
    225680            return false; 
     681        } 
     682        case(osgGA::GUIEventAdapter::FRAME): 
     683        { 
     684            if (_autoSteppingActive) 
     685            { 
     686                if (_firstTraversal) 
     687                { 
     688                    _firstTraversal = false; 
     689                    _previousTime = ea.time(); 
     690                } 
     691                else if (ea.time()-_previousTime>_timePerSlide) 
     692                { 
     693                    _previousTime = ea.time(); 
     694 
     695                    _album->nextPage(ea.time()+1.0f); 
     696                } 
     697            } 
     698             
     699            _album->setVisibility(); 
     700 
    226701        } 
    227702 
     
    237712    usage.addKeyboardMouseBinding("n","Advance to next image"); 
    238713    usage.addKeyboardMouseBinding("p","Move to previous image"); 
    239 } 
    240  
    241 void 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  
    264 void 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  
    274 void 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. 
    286 osg::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; 
    403714} 
    404715 
     
    462773    } 
    463774 
    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     } 
    475775 
    476776 
    477777    // now the windows have been realized we switch off the cursor to prevent it 
    478778    // distracting the people seeing the stereo images. 
     779    float fovx = 1.25f; 
    479780    float fovy = 1.0f; 
    480781    for( unsigned int i = 0; i < viewer.getCameraConfig()->getNumberOfCameras(); i++ ) 
     
    482783        Producer::Camera* cam = viewer.getCameraConfig()->getCamera(i); 
    483784        Producer::RenderSurface* rs = cam->getRenderSurface(); 
    484         rs->useCursor(false); 
     785        //rs->useCursor(false); 
     786        fovx = cam->getLensHorizontalFov(); 
    485787        fovy = cam->getLensVerticalFov(); 
    486788    } 
    487789 
    488790    float radius = 1.0f; 
     791    float width = 2*radius*tan(fovx*0.5f); 
    489792    float height = 2*radius*tan(fovy*0.5f); 
    490     float length = osg::PI*radius;  // half a cylinder. 
     793 
     794    osg::ref_ptr<Album> album = new Album(arguments,width,height); 
    491795 
    492796    // creat the scene from the file list. 
    493     osg::ref_ptr<osg::Switch> rootNode = createScene(fileList,height,length); 
     797    osg::ref_ptr<osg::Group> rootNode = album->getScene(); 
    494798     
    495799    if (!rootNode) return 0; 
     
    499803 
    500804    // set the scene to render 
    501     viewer.setSceneData(rootNode.get()); 
     805    viewer.setSceneData(album->getScene()); 
    502806 
    503807 
    504808    // set up the SlideEventHandler. 
    505     seh->set(rootNode.get(),timeDelayBetweenSlides,autoSteppingActive); 
     809    seh->set(album.get(),timeDelayBetweenSlides,autoSteppingActive); 
    506810     
    507811