Show
Ignore:
Timestamp:
03/22/03 21:35:11 (12 years ago)
Author:
robert
Message:

Revamp of the osgstereoimage demo to provide a presentation tool for up comming
"In Your Face" shows held at the Glasgow Science Center.

Files:
1 modified

Legend:

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

    r1728 r1736  
    1414#include <osgProducer/Viewer> 
    1515#include <osgDB/ReadFile> 
     16#include <osgDB/WriteFile> 
    1617#include <osgUtil/Optimizer> 
    1718 
     
    1920#include <osg/Notify> 
    2021#include <osg/MatrixTransform> 
    21  
     22#include <osg/Switch> 
     23#include <osg/TexMat> 
     24#include <osg/Texture2D> 
     25 
     26 
     27 
     28typedef std::vector<std::string> FileList; 
     29 
     30class SlideEventHandler : public osgGA::GUIEventHandler, public osg::NodeCallback 
     31{ 
     32public: 
     33 
     34    SlideEventHandler(); 
     35     
     36    META_Object(osgStereImageApp,SlideEventHandler); 
     37 
     38 
     39    void set(osg::Switch* sw, osg::TexMat* texmat,float timePerSlide, bool autoSteppingActive); 
     40 
     41    virtual void accept(osgGA::GUIEventHandlerVisitor& v) { v.visit(*this); } 
     42 
     43    virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&); 
     44     
     45    virtual void getUsage(osg::ApplicationUsage& usage) const; 
     46 
     47    virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); 
     48     
     49    void nextSlide(); 
     50     
     51    void previousSlide(); 
     52     
     53    void scaleImage(float s); 
     54     
     55    void rotateImage(float rx,float ry); 
     56 
     57 
     58protected: 
     59 
     60    ~SlideEventHandler() {} 
     61    SlideEventHandler(const SlideEventHandler&,const osg::CopyOp&) {} 
     62 
     63    osg::ref_ptr<osg::Switch>   _switch; 
     64    osg::ref_ptr<osg::TexMat>   _texmat; 
     65    bool                        _firstTraversal; 
     66    unsigned int                _activeSlide; 
     67    double                      _previousTime; 
     68    double                      _timePerSlide; 
     69    bool                        _autoSteppingActive; 
     70         
     71}; 
     72 
     73SlideEventHandler::SlideEventHandler(): 
     74    _switch(0), 
     75    _texmat(0), 
     76    _firstTraversal(true), 
     77    _activeSlide(0), 
     78    _previousTime(-1.0f), 
     79    _timePerSlide(5.0), 
     80    _autoSteppingActive(false) 
     81{ 
     82} 
     83 
     84void SlideEventHandler::set(osg::Switch* sw, osg::TexMat* texmat,float timePerSlide, bool autoSteppingActive) 
     85{ 
     86    _switch = sw; 
     87    _switch->setUpdateCallback(this); 
     88 
     89    _texmat = texmat; 
     90 
     91    _timePerSlide = timePerSlide; 
     92    _autoSteppingActive = autoSteppingActive;     
     93} 
     94 
     95bool SlideEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&) 
     96{ 
     97    switch(ea.getEventType()) 
     98    { 
     99        case(osgGA::GUIEventAdapter::KEYDOWN): 
     100        { 
     101            if (ea.getKey()=='a') 
     102            { 
     103                _autoSteppingActive = !_autoSteppingActive; 
     104                _previousTime = ea.time(); 
     105                return true; 
     106            } 
     107            else if (ea.getKey()=='n') 
     108            { 
     109                nextSlide(); 
     110                return true; 
     111            } 
     112            else if (ea.getKey()=='p') 
     113            { 
     114                previousSlide(); 
     115                return true; 
     116            } 
     117            else if (ea.getKey()=='z') 
     118            { 
     119                scaleImage(0.99f); 
     120                return true; 
     121            } 
     122            else if (ea.getKey()=='x') 
     123            { 
     124                scaleImage(1.01f); 
     125                return true; 
     126            } 
     127            else if (ea.getKey()==' ') 
     128            { 
     129                if (_texmat.valid()) _texmat->setMatrix(osg::Matrix::identity()); 
     130                return true; 
     131            } 
     132            return false; 
     133        } 
     134        case(osgGA::GUIEventAdapter::DRAG): 
     135        case(osgGA::GUIEventAdapter::MOVE): 
     136        { 
     137            static int px = ea.getX(); 
     138            static int py = ea.getY(); 
     139             
     140            int dx = ea.getX()-px; 
     141            int dy = ea.getY()-py; 
     142             
     143            px = ea.getX(); 
     144            py = ea.getY(); 
     145             
     146            rotateImage((float)dx/(float)(ea.getXmax()-ea.getXmin()),(float)dy/(float)(ea.getYmax()-ea.getYmin())); 
     147             
     148            return true; 
     149        } 
     150 
     151        default: 
     152            return false; 
     153    } 
     154} 
     155 
     156void SlideEventHandler::getUsage(osg::ApplicationUsage& usage) const 
     157{ 
     158    usage.addKeyboardMouseBinding("Space","Reset the image position to center"); 
     159    usage.addKeyboardMouseBinding("a","Toggle on/off the automatic advancement for image to image"); 
     160    usage.addKeyboardMouseBinding("n","Advance to next image"); 
     161    usage.addKeyboardMouseBinding("p","Move to previous image"); 
     162    usage.addKeyboardMouseBinding("z","Zoom into the image"); 
     163    usage.addKeyboardMouseBinding("x","Zoom out of the image"); 
     164} 
     165 
     166void SlideEventHandler::operator()(osg::Node* node, osg::NodeVisitor* nv) 
     167{ 
     168    if (_autoSteppingActive && nv->getFrameStamp()) 
     169    { 
     170        double time = nv->getFrameStamp()->getReferenceTime(); 
     171         
     172        if (_firstTraversal) 
     173        { 
     174            _firstTraversal = false; 
     175            _previousTime = time; 
     176        } 
     177        else if (time-_previousTime>_timePerSlide) 
     178        { 
     179            _previousTime = time; 
     180             
     181            nextSlide(); 
     182        } 
     183         
     184    } 
     185 
     186    traverse(node,nv); 
     187} 
     188 
     189void SlideEventHandler::nextSlide() 
     190{ 
     191    if (_switch->getNumChildren()==0) return; 
     192 
     193    ++_activeSlide; 
     194    if (_activeSlide>=_switch->getNumChildren()) _activeSlide = 0; 
     195 
     196    _switch->setSingleChildOn(_activeSlide); 
     197} 
     198 
     199void SlideEventHandler::previousSlide() 
     200{ 
     201    if (_switch->getNumChildren()==0) return; 
     202 
     203    if (_activeSlide==0) _activeSlide = _switch->getNumChildren()-1; 
     204    else --_activeSlide; 
     205 
     206    _switch->setSingleChildOn(_activeSlide); 
     207} 
     208 
     209void SlideEventHandler::scaleImage(float s) 
     210{ 
     211    if (_texmat.valid()) 
     212    { 
     213        _texmat->setMatrix(_texmat->getMatrix()*osg::Matrix::translate(-0.5f,-0.5f,0.0f)*osg::Matrix::scale(s,s,1.0f)*osg::Matrix::translate(0.5f,0.5f,0.0f)); 
     214    } 
     215} 
     216 
     217void SlideEventHandler::rotateImage(float rx,float ry) 
     218{ 
     219    if (_texmat.valid()) 
     220    { 
     221        const float scale = 0.5f; 
     222        _texmat->setMatrix(_texmat->getMatrix()*osg::Matrix::translate(-rx*scale,ry*scale,0.0f)); 
     223    } 
     224} 
     225 
     226osg::Geode* createSectorForImage(osg::Image* image,float s,float t, float radius, float height, float length) 
     227{ 
     228 
     229    int numSegments = 20; 
     230    float Theta = length/radius; 
     231    float dTheta = Theta/(float)(numSegments-1); 
     232     
     233    float ThetaZero = height*s/(t*radius); 
     234     
     235    // set up the texture. 
     236    osg::Texture2D* texture = new osg::Texture2D; 
     237    texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); 
     238    texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); 
     239    texture->setImage(image); 
     240 
     241    // set up the drawstate. 
     242    osg::StateSet* dstate = new osg::StateSet; 
     243    dstate->setMode(GL_CULL_FACE,osg::StateAttribute::OFF); 
     244    dstate->setMode(GL_LIGHTING,osg::StateAttribute::OFF); 
     245    dstate->setTextureAttributeAndModes(0, texture,osg::StateAttribute::ON); 
     246 
     247    // set up the geoset. 
     248    osg::Geometry* geom = new osg::Geometry; 
     249    geom->setStateSet(dstate); 
     250 
     251    osg::Vec3Array* coords = new osg::Vec3Array(); 
     252    osg::Vec2Array* tcoords = new osg::Vec2Array(); 
     253    
     254    int i; 
     255    float angle = -Theta/2.0f; 
     256    for(i=0; 
     257        i<numSegments; 
     258        ++i, angle+=dTheta) 
     259    { 
     260        coords->push_back(osg::Vec3(sinf(angle)*radius,cosf(angle)*radius,height*0.5f)); // top 
     261        coords->push_back(osg::Vec3(sinf(angle)*radius,cosf(angle)*radius,-height*0.5f)); // bottom. 
     262         
     263        tcoords->push_back(osg::Vec2(angle/ThetaZero+0.5f,1.0f)); // top 
     264        tcoords->push_back(osg::Vec2(angle/ThetaZero+0.5f,0.0f)); // bottom. 
     265 
     266    } 
     267 
     268    osg::Vec4Array* colors = new osg::Vec4Array(); 
     269    colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); 
     270 
     271    osg::DrawArrays* elements = new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,0,coords->size()); 
     272 
     273     
     274 
     275    geom->setVertexArray(coords); 
     276    geom->setTexCoordArray(0,tcoords); 
     277    geom->setColorArray(colors); 
     278    geom->setColorBinding(osg::Geometry::BIND_OVERALL); 
     279 
     280    geom->addPrimitiveSet(elements); 
     281 
     282    // set up the geode. 
     283    osg::Geode* geode = new osg::Geode; 
     284    geode->addDrawable(geom); 
     285 
     286    return geode; 
     287 
     288} 
     289 
     290// create a switch containing a set of child each containing a  
     291// stereo image pair. 
     292osg::Switch* createScene(const FileList& fileList, float radius, float height, float length) 
     293{ 
     294    osg::Switch* sw = new osg::Switch; 
     295 
     296    // load the images. 
     297    for(unsigned int i=0;i+1<fileList.size();i+=2) 
     298    { 
     299        osg::ref_ptr<osg::Image> imageLeft = osgDB::readImageFile(fileList[i]); 
     300        osg::ref_ptr<osg::Image> imageRight = osgDB::readImageFile(fileList[i+1]); 
     301        if (imageLeft.valid() && imageRight.valid()) 
     302        { 
     303            float average_s = (imageLeft->s()+imageRight->s())*0.5f; 
     304            float average_t = (imageLeft->t()+imageRight->t())*0.5f; 
     305 
     306            osg::Geode* geodeLeft = createSectorForImage(imageLeft.get(),average_s,average_t, radius, height, length); 
     307            geodeLeft->setNodeMask(0x01); 
     308 
     309            osg::Geode* geodeRight = createSectorForImage(imageRight.get(),average_s,average_t, radius, height, length); 
     310            geodeRight->setNodeMask(0x02); 
     311 
     312            osg::ref_ptr<osg::Group> imageGroup = new osg::Group; 
     313             
     314            imageGroup->addChild(geodeLeft); 
     315            imageGroup->addChild(geodeRight); 
     316             
     317            sw->addChild(imageGroup.get()); 
     318        } 
     319        else 
     320        { 
     321            std::cout << "Warning: Unable to load both image files, '"<<fileList[i]<<"' & '"<<fileList[i+1]<<"', required for stereo imaging."<<std::endl; 
     322        } 
     323    } 
     324 
     325 
     326    if (sw->getNumChildren()>0) 
     327    { 
     328        // select first child. 
     329        sw->setSingleChildOn(0); 
     330    } 
     331 
     332    return sw; 
     333} 
    22334 
    23335int main( int argc, char **argv ) 
     
    29341    // set up the usage document, in case we need to print out how to use this program. 
    30342    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getProgramName()+" [options] image_file_left_eye image_file_right_eye"); 
     343    arguments.getApplicationUsage()->addCommandLineOption("-d <float>","Time delay in sceonds between the display of successive image pairs when in auto advance mode."); 
     344    arguments.getApplicationUsage()->addCommandLineOption("-a","Enter auto advance of image pairs on start up."); 
    31345    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information"); 
    32346     
     
    36350 
    37351    // set up the value with sensible default event handlers. 
    38     viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS); 
     352    viewer.setUpViewer(osgProducer::Viewer::ESCAPE_SETS_DONE); 
     353 
     354    // register the handler to add keyboard and mosue handling. 
     355    SlideEventHandler* seh = new SlideEventHandler(); 
     356    viewer.getEventHandlerList().push_front(seh); 
     357 
    39358 
    40359    // get details on keyboard and mouse bindings used by the viewer. 
    41360    viewer.getUsage(*arguments.getApplicationUsage()); 
    42361 
     362    // read any time delay argument. 
     363    float timeDelayBetweenSlides = 5.0f; 
     364    while (arguments.read("-d",timeDelayBetweenSlides)) {} 
     365 
     366    bool autoSteppingActive = false; 
     367    while (arguments.read("-a")) autoSteppingActive = true; 
     368 
     369 
    43370    // if user request help write it out to cout. 
    44371    if (arguments.read("-h") || arguments.read("--help")) 
     
    59386 
    60387    // extract the filenames from the arguments list. 
    61     std::string fileLeft,fileRight; 
     388    FileList fileList; 
    62389    for(int pos=1;pos<arguments.argc();++pos) 
    63390    { 
    64         if (arguments.isString(pos)) 
    65         { 
    66             if (fileLeft.empty()) fileLeft = arguments[pos]; 
    67             else if (fileRight.empty()) fileRight = arguments[pos]; 
    68         } 
    69     } 
    70  
    71  
    72     if (fileLeft.empty() || fileRight.empty()) 
    73     { 
    74         std::cout << arguments.getProgramName() <<": Please specify two image files required for stereo imaging."<<std::endl; 
    75         return 1; 
    76     } 
    77      
    78     osg::Image* imageLeft = osgDB::readImageFile(fileLeft); 
    79     osg::Image* imageRight = osgDB::readImageFile(fileRight); 
    80      
    81     if (!imageLeft || !imageRight) 
    82     {     
    83         std::cout << arguments.getProgramName() <<": Unable to load two image files required for stereo imaging."<<std::endl; 
    84         return 1; 
    85     } 
    86      
    87     float average_s = (imageLeft->s()+imageRight->s())*0.5f; 
    88     float average_t = (imageLeft->t()+imageRight->t())*0.5f; 
    89  
    90     osg::Geode* geodeLeft = osg::createGeodeForImage(imageLeft,average_s,average_t); 
    91     geodeLeft->setNodeMask(0x01); 
    92  
    93     osg::Geode* geodeRight = osg::createGeodeForImage(imageRight,average_s,average_t); 
    94     geodeRight->setNodeMask(0x02); 
    95  
    96     osg::ref_ptr<osg::Group> rootNode = new osg::Group; 
    97     rootNode->addChild(geodeLeft); 
    98     rootNode->addChild(geodeRight); 
    99  
    100     // set the scene to render 
    101     viewer.setSceneData(rootNode.get()); 
     391        if (arguments.isString(pos)) fileList.push_back(arguments[pos]); 
     392    } 
     393 
    102394 
    103395    // set up the use of stereo by default. 
     
    109401    viewer.realize(Producer::CameraGroup::ThreadPerCamera); 
    110402 
     403    // now the windows have been realized we switch off the cursor to prevent it 
     404    // distracting the people seeing the stereo images. 
     405    float fovy = 1.0f; 
     406    for( unsigned int i = 0; i < viewer.getCameraConfig()->getNumberOfCameras(); i++ ) 
     407    { 
     408        Producer::Camera* cam = viewer.getCameraConfig()->getCamera(i); 
     409        Producer::RenderSurface* rs = cam->getRenderSurface(); 
     410        rs->useCursor(false); 
     411        fovy = cam->getLensVerticalFov(); 
     412    } 
     413 
     414    float radius = 1.0f; 
     415    float height = 2*radius*tanf(fovy*0.5f); 
     416    float length = osg::PI*radius;  // half a cylinder. 
     417 
     418    // creat the scene from the file list. 
     419    osg::ref_ptr<osg::Switch> rootNode = createScene(fileList,radius,height,length); 
     420 
     421    // use a texure matrix to control the placement of the image. 
     422    osg::StateSet* stateset = rootNode->getOrCreateStateSet(); 
     423    osg::TexMat* texmat = new osg::TexMat; 
     424    stateset->setTextureAttribute(0,texmat); 
     425 
     426 
     427    osgDB::writeNodeFile(*rootNode,"test.osg"); 
     428 
     429    // set the scene to render 
     430    viewer.setSceneData(rootNode.get()); 
     431 
     432 
    111433    // set all the sceneview's up so that their left and right add cull masks are set up. 
    112434    for(osgProducer::OsgCameraGroup::SceneHandlerList::iterator itr=viewer.getSceneHandlerList().begin(); 
     
    118440        sceneview->setCullMaskLeft(0x00000001); 
    119441        sceneview->setCullMaskRight(0x00000002); 
    120     } 
    121  
    122  
     442        sceneview->setFusionDistance(osgUtil::SceneView::USE_FUSION_DISTANCE_VALUE,radius); 
     443        sceneview->setCamera(0); 
     444    } 
     445 
     446 
     447    // set up the SlideEventHandler. 
     448    seh->set(rootNode.get(),texmat,timeDelayBetweenSlides,autoSteppingActive); 
     449     
     450     
     451    osg::Matrix homePosition; 
     452    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)); 
     453         
    123454    while( !viewer.done() ) 
    124455    { 
     
    130461        viewer.update(); 
    131462          
     463        viewer.setView(homePosition.ptr()); 
     464 
    132465        // fire off the cull and draw traversals of the scene. 
    133466        viewer.frame();