Show
Ignore:
Timestamp:
09/25/07 17:01:11 (7 years ago)
Author:
robert
Message:

Removed all dome distortion correction code as this is now part of the core osgViewer.

Added viewer mode where movies are made fullscreen. One can use the old interactive
camera mode by using --interactive parameter on the command line.

Files:
1 modified

Legend:

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

    r7475 r7477  
    268268 
    269269 
    270 osg::Geometry* myCreateTexturedQuadGeometry(const osg::Vec3& pos,float width,float height, osg::Image* image, bool useTextureRectangle) 
     270osg::Geometry* myCreateTexturedQuadGeometry(const osg::Vec3& pos,float width,float height, osg::Image* image, bool useTextureRectangle, bool xyPlane) 
    271271{ 
    272272    bool flip = image->getOrigin()==osg::Image::TOP_LEFT; 
     
    275275        osg::Geometry* pictureQuad = osg::createTexturedQuadGeometry(pos, 
    276276                                           osg::Vec3(width,0.0f,0.0f), 
    277                                            osg::Vec3(0.0f,0.0f,height), 
     277                                           xyPlane ? osg::Vec3(0.0f,height,0.0f) : osg::Vec3(0.0f,0.0f,height), 
    278278                                           0.0f, flip ? image->t() : 0.0, image->s(), flip ? 0.0 : image->t()); 
    279279 
     
    293293        osg::Geometry* pictureQuad = osg::createTexturedQuadGeometry(pos, 
    294294                                           osg::Vec3(width,0.0f,0.0f), 
    295                                            osg::Vec3(0.0f,0.0f,height), 
     295                                           xyPlane ? osg::Vec3(0.0f,height,0.0f) : osg::Vec3(0.0f,0.0f,height), 
    296296                                           0.0f, flip ? 1.0f : 0.0f , 1.0f, flip ? 0.0f : 1.0f); 
    297297                                     
     
    308308        return pictureQuad; 
    309309    } 
    310 } 
    311  
    312 class DomeModel 
    313 { 
    314 public: 
    315  
    316     DomeModel(osg::ArgumentParser& arguments): 
    317         sphere_radius(1.0), 
    318         collar_radius(0.45), 
    319         rotationDegrees(180.0), 
    320         distance(0.0), 
    321         flip(false), 
    322         texcoord_flip(false) 
    323     { 
    324         if (arguments.read("--radius", sphere_radius)) {} 
    325         if (arguments.read("--collar", collar_radius)) {} 
    326         if (arguments.read("--rotation", rotationDegrees)) {} 
    327  
    328         distance = sqrt(sphere_radius*sphere_radius - collar_radius*collar_radius); 
    329         if (arguments.read("--distance", distance)) {} 
    330  
    331         if (arguments.read("--flip")) { flip = true; } 
    332     } 
    333      
    334     double sphere_radius; 
    335     double collar_radius; 
    336     double rotationDegrees; 
    337     double distance; 
    338     bool flip; 
    339     bool texcoord_flip; 
    340  
    341 }; 
    342  
    343  
    344 osg::Geometry* createDomeDistortionMesh(const osg::Vec3& origin, const osg::Vec3& widthVector, const osg::Vec3& heightVector, DomeModel& domeModel) 
    345 { 
    346     osg::Vec3d center(0.0,0.0,0.0); 
    347     osg::Vec3d eye(0.0,0.0,0.0); 
    348      
    349     bool centerProjection = false; 
    350  
    351     osg::Vec3d projector = eye - osg::Vec3d(0.0,0.0, domeModel.distance); 
    352      
    353      
    354     osg::notify(osg::NOTICE)<<"Projector position = "<<projector<<std::endl; 
    355     osg::notify(osg::NOTICE)<<"distance = "<<domeModel.distance<<std::endl; 
    356  
    357  
    358     // create the quad to visualize. 
    359     osg::Geometry* geometry = new osg::Geometry(); 
    360  
    361     geometry->setSupportsDisplayList(false); 
    362  
    363     osg::Vec3 xAxis(widthVector); 
    364     float width = widthVector.length(); 
    365     xAxis /= width; 
    366  
    367     osg::Vec3 yAxis(heightVector); 
    368     float height = heightVector.length(); 
    369     yAxis /= height; 
    370      
    371     int noSteps = 160; 
    372  
    373     osg::Vec3Array* vertices = new osg::Vec3Array; 
    374     osg::Vec2Array* texcoords = new osg::Vec2Array; 
    375     osg::Vec4Array* colors = new osg::Vec4Array; 
    376  
    377     osg::Vec3 bottom = origin; 
    378     osg::Vec3 dx = xAxis*(width/((float)(noSteps-2))); 
    379     osg::Vec3 dy = yAxis*(height/((float)(noSteps-1))); 
    380      
    381     osg::Vec3 top = origin + yAxis*height; 
    382  
    383     osg::Vec3d screenCenter = origin + widthVector*0.5f + heightVector*0.5f; 
    384     float screenRadius = heightVector.length() * 0.5f; 
    385  
    386     double rotation = osg::DegreesToRadians(domeModel.rotationDegrees); 
    387  
    388     osg::Vec3 cursor = bottom; 
    389     int i,j; 
    390      
    391     int midSteps = noSteps/2; 
    392      
    393     for(i=0;i<midSteps;++i) 
    394     { 
    395         osg::Vec3 cursor = bottom+dy*(float)i; 
    396         for(j=0;j<midSteps;++j) 
    397         { 
    398             osg::Vec2 delta(cursor.x() - screenCenter.x(), cursor.y() - screenCenter.y()); 
    399             double theta = atan2(delta.x(), -delta.y()); 
    400             theta += 2*osg::PI; 
    401  
    402             double phi = osg::PI_2 * delta.length() / screenRadius; 
    403             if (phi > osg::PI_2) phi = osg::PI_2; 
    404  
    405             double f = domeModel.distance * sin(phi); 
    406             double e = domeModel.distance * cos(phi) + sqrt( domeModel.sphere_radius*domeModel.sphere_radius - f*f); 
    407             double l = e * cos(phi); 
    408             double h = e * sin(phi); 
    409             double gamma = atan2(h, l-domeModel.distance); 
    410  
    411             osg::Vec2 texcoord(theta/(2.0*osg::PI), 1.0-gamma/osg::PI); 
    412  
    413             // osg::notify(osg::NOTICE)<<"cursor = "<<cursor<< " theta = "<<theta<< "phi="<<phi<<" gamma = "<<gamma<<" texcoord="<<texcoord<<std::endl; 
    414  
    415             if (domeModel.flip) 
    416                 vertices->push_back(osg::Vec3(cursor.x(), top.y()-(cursor.y()-origin.y()),cursor.z())); 
    417             else 
    418                 vertices->push_back(cursor); 
    419              
    420             colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); 
    421             texcoords->push_back( domeModel.texcoord_flip ? osg::Vec2(texcoord.x(), 1.0f - texcoord.y()) : texcoord); 
    422  
    423             if (j+1<midSteps) cursor += dx; 
    424         } 
    425  
    426         for(;j<noSteps;++j) 
    427         { 
    428             osg::Vec2 delta(cursor.x() - screenCenter.x(), cursor.y() - screenCenter.y()); 
    429             double theta = atan2(delta.x(), -delta.y()); 
    430             double phi = osg::PI_2 * delta.length() / screenRadius; 
    431             if (phi > osg::PI_2) phi = osg::PI_2; 
    432  
    433             double f = domeModel.distance * sin(phi); 
    434             double e = domeModel.distance * cos(phi) + sqrt( domeModel.sphere_radius*domeModel.sphere_radius - f*f); 
    435             double l = e * cos(phi); 
    436             double h = e * sin(phi); 
    437             double gamma = atan2(h, l-domeModel.distance); 
    438  
    439             osg::Vec2 texcoord(theta/(2.0*osg::PI), 1.0-gamma/osg::PI); 
    440  
    441             // osg::notify(osg::NOTICE)<<"cursor = "<<cursor<< " theta = "<<theta<< "phi="<<phi<<" gamma = "<<gamma<<" texcoord="<<texcoord<<std::endl; 
    442  
    443             if (domeModel.flip) 
    444                 vertices->push_back(osg::Vec3(cursor.x(), top.y()-(cursor.y()-origin.y()),cursor.z())); 
    445             else 
    446                 vertices->push_back(cursor); 
    447  
    448             colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); 
    449             texcoords->push_back( domeModel.texcoord_flip ? osg::Vec2(texcoord.x(), 1.0f - texcoord.y()) : texcoord); 
    450  
    451             cursor += dx; 
    452         } 
    453         // osg::notify(osg::NOTICE)<<std::endl; 
    454     } 
    455      
    456     for(;i<noSteps;++i) 
    457     { 
    458         osg::Vec3 cursor = bottom+dy*(float)i; 
    459         for(j=0;j<noSteps;++j) 
    460         { 
    461             osg::Vec2 delta(cursor.x() - screenCenter.x(), cursor.y() - screenCenter.y()); 
    462             double theta = atan2(delta.x(), -delta.y()); 
    463             if (theta<0.0) theta += 2*osg::PI; 
    464             double phi = osg::PI_2 * delta.length() / screenRadius; 
    465             if (phi > osg::PI_2) phi = osg::PI_2; 
    466  
    467             double f = domeModel.distance * sin(phi); 
    468             double e = domeModel.distance * cos(phi) + sqrt( domeModel.sphere_radius*domeModel.sphere_radius - f*f); 
    469             double l = e * cos(phi); 
    470             double h = e * sin(phi); 
    471             double gamma = atan2(h, l-domeModel.distance); 
    472  
    473             osg::Vec2 texcoord(theta/(2.0*osg::PI), 1.0-gamma/osg::PI); 
    474  
    475             // osg::notify(osg::NOTICE)<<"cursor = "<<cursor<< " theta = "<<theta<< "phi="<<phi<<" gamma = "<<gamma<<" texcoord="<<texcoord<<std::endl; 
    476  
    477             if (domeModel.flip) 
    478                 vertices->push_back(osg::Vec3(cursor.x(), top.y()-(cursor.y()-origin.y()),cursor.z())); 
    479             else 
    480                 vertices->push_back(cursor); 
    481  
    482             colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); 
    483             texcoords->push_back( domeModel.texcoord_flip ? osg::Vec2(texcoord.x(), 1.0f - texcoord.y()) : texcoord); 
    484  
    485             cursor += dx; 
    486         } 
    487  
    488         // osg::notify(osg::NOTICE)<<std::endl; 
    489     } 
    490  
    491     // pass the created vertex array to the points geometry object. 
    492     geometry->setVertexArray(vertices); 
    493  
    494     geometry->setColorArray(colors); 
    495     geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX); 
    496  
    497     geometry->setTexCoordArray(0,texcoords); 
    498  
    499     for(i=0;i<noSteps-1;++i) 
    500     { 
    501         osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(osg::PrimitiveSet::QUAD_STRIP); 
    502         for(j=0;j<noSteps;++j) 
    503         { 
    504             elements->push_back(j+(i+1)*noSteps); 
    505             elements->push_back(j+(i)*noSteps); 
    506         } 
    507         geometry->addPrimitiveSet(elements); 
    508     } 
    509      
    510     return geometry; 
    511 } 
    512  
    513  
    514 void setDomeCorrection(osgViewer::Viewer& viewer, osg::ArgumentParser& arguments) 
    515 { 
    516     // enforce single threading right now to avoid double buffering of RTT texture 
    517     viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded); 
    518   
    519     osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface(); 
    520     if (!wsi)  
    521     { 
    522         osg::notify(osg::NOTICE)<<"Error, no WindowSystemInterface available, cannot create windows."<<std::endl; 
    523         return; 
    524     } 
    525  
    526     unsigned int screenNum = 0; 
    527     while (arguments.read("--screen",screenNum)) {} 
    528  
    529  
    530     unsigned int width, height; 
    531     wsi->getScreenResolution(osg::GraphicsContext::ScreenIdentifier(screenNum), width, height); 
    532  
    533     while (arguments.read("--width",width)) {} 
    534     while (arguments.read("--height",height)) {} 
    535  
    536     DomeModel domeModel(arguments); 
    537  
    538     osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits; 
    539     traits->screenNum = screenNum; 
    540     traits->x = 0; 
    541     traits->y = 0; 
    542     traits->width = width; 
    543     traits->height = height; 
    544     traits->windowDecoration = false; 
    545     traits->doubleBuffer = true; 
    546     traits->sharedContext = 0; 
    547      
    548      
    549  
    550     osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get()); 
    551     if (!gc) 
    552     { 
    553         osg::notify(osg::NOTICE)<<"GraphicsWindow has not been created successfully."<<std::endl; 
    554         return; 
    555     } 
    556  
    557     osg::Texture* texture = 0; 
    558     for(int i=1;i<arguments.argc() && !texture;++i) 
    559     { 
    560         if (arguments.isString(i)) 
    561         { 
    562             osg::Image* image = osgDB::readImageFile(arguments[i]); 
    563             osg::ImageStream* imagestream = dynamic_cast<osg::ImageStream*>(image); 
    564             if (imagestream) imagestream->play(); 
    565  
    566             if (image) 
    567             { 
    568                 domeModel.texcoord_flip = image->getOrigin()==osg::Image::TOP_LEFT; 
    569              
    570 #if 1             
    571                 texture = new osg::TextureRectangle(image); 
    572 #else 
    573                 texture = new osg::Texture2D(image); 
    574 #endif 
    575             } 
    576         } 
    577     } 
    578      
    579     if (!texture) 
    580     { 
    581         return; 
    582     } 
    583  
    584     // distortion correction set up. 
    585     { 
    586         osg::Geode* geode = new osg::Geode(); 
    587         geode->addDrawable( createDomeDistortionMesh(osg::Vec3(0.0f,0.0f,0.0f), osg::Vec3(width,0.0f,0.0f), osg::Vec3(0.0f,height,0.0f), domeModel) ); 
    588  
    589         // new we need to add the texture to the mesh, we do so by creating a  
    590         // StateSet to contain the Texture StateAttribute. 
    591         osg::StateSet* stateset = geode->getOrCreateStateSet(); 
    592         stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); 
    593         texture->setMaxAnisotropy(16.0f); 
    594         stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF); 
    595 #if 1         
    596         osg::TexMat* texmat = new osg::TexMat; 
    597         texmat->setScaleByTextureRectangleSize(true); 
    598         stateset->setTextureAttributeAndModes(0, texmat, osg::StateAttribute::ON); 
    599 #endif 
    600         osg::ref_ptr<osg::Camera> camera = new osg::Camera; 
    601         camera->setGraphicsContext(gc.get()); 
    602         camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT ); 
    603         camera->setClearColor( osg::Vec4(0.1,0.1,1.0,1.0) ); 
    604         camera->setViewport(new osg::Viewport(0, 0, width, height)); 
    605         GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT; 
    606         camera->setDrawBuffer(buffer); 
    607         camera->setReadBuffer(buffer); 
    608         camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); 
    609         camera->setAllowEventFocus(false); 
    610         //camera->setInheritanceMask(camera->getInheritanceMask() & ~osg::CullSettings::CLEAR_COLOR & ~osg::CullSettings::COMPUTE_NEAR_FAR_MODE); 
    611         //camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR); 
    612          
    613         camera->setProjectionMatrixAsOrtho2D(0,width,0,height); 
    614         camera->setViewMatrix(osg::Matrix::identity()); 
    615  
    616         // add subgraph to render 
    617         // camera->addChild(geode); 
    618          
    619         camera->setName("DistortionCorrectionCamera"); 
    620  
    621         viewer.addSlave(camera.get(), osg::Matrixd(), osg::Matrixd(), true); 
    622  
    623         viewer.setSceneData(geode); 
    624     } 
    625      
    626      
    627     viewer.getCamera()->setNearFarRatio(0.0001f); 
    628310} 
    629311 
     
    641323    arguments.getApplicationUsage()->addCommandLineOption("--shader","Use shaders to post process the video."); 
    642324    arguments.getApplicationUsage()->addCommandLineOption("--dome","Use full dome distortion correction."); 
     325    arguments.getApplicationUsage()->addCommandLineOption("--interactive","Use camera manipulator to allow movement around movie.."); 
    643326     
    644327    bool useTextureRectangle = true; 
     
    664347    } 
    665348 
    666  
    667  
    668     if (arguments.read("--dome") || arguments.read("--puffer") ) 
    669     {     
    670         setDomeCorrection(viewer, arguments); 
    671     } 
    672     else 
    673     { 
    674         osg::ref_ptr<osg::Geode> geode = new osg::Geode; 
    675         osg::Vec3 pos(0.0f,0.0f,0.0f); 
    676  
    677         osg::StateSet* stateset = geode->getOrCreateStateSet(); 
    678         stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF); 
    679  
    680         if (useShader) 
    681         { 
    682             //useTextureRectangle = false; 
    683  
    684             static const char *shaderSourceTextureRec = { 
    685                 "uniform vec4 cutoff_color;\n" 
    686                 "uniform samplerRect movie_texture;\n" 
    687                 "void main(void)\n" 
    688                 "{\n" 
    689                 "    vec4 texture_color = textureRect(movie_texture, gl_TexCoord[0]); \n" 
    690                 "    if (all(lessThanEqual(texture_color,cutoff_color))) discard; \n" 
    691                 "    gl_FragColor = texture_color;\n" 
    692                 "}\n" 
    693             }; 
    694  
    695             static const char *shaderSourceTexture2D = { 
    696                 "uniform vec4 cutoff_color;\n" 
    697                 "uniform sampler2D movie_texture;\n" 
    698                 "void main(void)\n" 
    699                 "{\n" 
    700                 "    vec4 texture_color = texture2D(movie_texture, gl_TexCoord[0]); \n" 
    701                 "    if (all(lessThanEqual(texture_color,cutoff_color))) discard; \n" 
    702                 "    gl_FragColor = texture_color;\n" 
    703                 "}\n" 
    704             }; 
    705  
    706             osg::Program* program = new osg::Program; 
    707  
    708             program->addShader(new osg::Shader(osg::Shader::FRAGMENT, 
    709                                                useTextureRectangle ? shaderSourceTextureRec : shaderSourceTexture2D)); 
    710  
    711             stateset->addUniform(new osg::Uniform("cutoff_color",osg::Vec4(0.1f,0.1f,0.1f,1.0f))); 
    712             stateset->addUniform(new osg::Uniform("movie_texture",0)); 
    713  
    714             stateset->setAttribute(program); 
    715  
    716         } 
    717  
    718         for(int i=1;i<arguments.argc();++i) 
    719         { 
    720             if (arguments.isString(i)) 
    721             { 
    722                 osg::Image* image = osgDB::readImageFile(arguments[i]); 
    723                 osg::ImageStream* imagestream = dynamic_cast<osg::ImageStream*>(image); 
    724                 if (imagestream) imagestream->play(); 
    725  
    726                 if (image) 
    727                 { 
    728                     geode->addDrawable(myCreateTexturedQuadGeometry(pos,image->s(),image->t(),image, useTextureRectangle)); 
    729  
    730                     pos.z() += image->t()*1.5f; 
    731                 } 
    732                 else 
    733                 { 
    734                     std::cout<<"Unable to read file "<<arguments[i]<<std::endl; 
    735                 }             
    736             } 
    737         } 
    738  
    739         // set the scene to render 
    740         viewer.setSceneData(geode.get()); 
    741  
    742         if (viewer.getSceneData()==0) 
    743         { 
    744             arguments.getApplicationUsage()->write(std::cout); 
    745             return 1; 
    746         } 
    747     } 
    748      
     349    bool fullscreen = !arguments.read("--interactive"); 
     350 
     351 
     352    osg::ref_ptr<osg::Geode> geode = new osg::Geode; 
     353 
     354    osg::StateSet* stateset = geode->getOrCreateStateSet(); 
     355    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF); 
     356 
     357    if (useShader) 
     358    { 
     359        //useTextureRectangle = false; 
     360 
     361        static const char *shaderSourceTextureRec = { 
     362            "uniform vec4 cutoff_color;\n" 
     363            "uniform samplerRect movie_texture;\n" 
     364            "void main(void)\n" 
     365            "{\n" 
     366            "    vec4 texture_color = textureRect(movie_texture, gl_TexCoord[0]); \n" 
     367            "    if (all(lessThanEqual(texture_color,cutoff_color))) discard; \n" 
     368            "    gl_FragColor = texture_color;\n" 
     369            "}\n" 
     370        }; 
     371 
     372        static const char *shaderSourceTexture2D = { 
     373            "uniform vec4 cutoff_color;\n" 
     374            "uniform sampler2D movie_texture;\n" 
     375            "void main(void)\n" 
     376            "{\n" 
     377            "    vec4 texture_color = texture2D(movie_texture, gl_TexCoord[0]); \n" 
     378            "    if (all(lessThanEqual(texture_color,cutoff_color))) discard; \n" 
     379            "    gl_FragColor = texture_color;\n" 
     380            "}\n" 
     381        }; 
     382 
     383        osg::Program* program = new osg::Program; 
     384 
     385        program->addShader(new osg::Shader(osg::Shader::FRAGMENT, 
     386                                           useTextureRectangle ? shaderSourceTextureRec : shaderSourceTexture2D)); 
     387 
     388        stateset->addUniform(new osg::Uniform("cutoff_color",osg::Vec4(0.1f,0.1f,0.1f,1.0f))); 
     389        stateset->addUniform(new osg::Uniform("movie_texture",0)); 
     390 
     391        stateset->setAttribute(program); 
     392 
     393    } 
     394 
     395    osg::Vec3 pos(0.0f,0.0f,0.0f); 
     396    osg::Vec3 topleft = pos; 
     397    osg::Vec3 bottomright = pos; 
     398     
     399    bool xyPlane = fullscreen; 
     400     
     401    for(int i=1;i<arguments.argc();++i) 
     402    { 
     403        if (arguments.isString(i)) 
     404        { 
     405            osg::Image* image = osgDB::readImageFile(arguments[i]); 
     406            osg::ImageStream* imagestream = dynamic_cast<osg::ImageStream*>(image); 
     407            if (imagestream) imagestream->play(); 
     408 
     409            if (image) 
     410            { 
     411                geode->addDrawable(myCreateTexturedQuadGeometry(pos,image->s(),image->t(),image, useTextureRectangle, xyPlane)); 
     412         
     413                bottomright = pos + osg::Vec3(static_cast<float>(image->s()),static_cast<float>(image->t()),0.0f); 
     414 
     415                pos.y() += image->t()*1.5f; 
     416            } 
     417            else 
     418            { 
     419                std::cout<<"Unable to read file "<<arguments[i]<<std::endl; 
     420            }             
     421        } 
     422    } 
     423     
     424    // set the scene to render 
     425    viewer.setSceneData(geode.get()); 
     426 
     427    if (viewer.getSceneData()==0) 
     428    { 
     429        arguments.getApplicationUsage()->write(std::cout); 
     430        return 1; 
     431    } 
    749432 
    750433    // pass the model to the MovieEventHandler so it can pick out ImageStream's to manipulate. 
     
    763446    } 
    764447 
    765  
    766  
    767     // create the windows and run the threads. 
    768     return viewer.run(); 
    769  
    770  
     448    if (fullscreen) 
     449    { 
     450        viewer.realize(); 
     451 
     452        viewer.getCamera()->setViewMatrix(osg::Matrix::identity()); 
     453        viewer.getCamera()->setProjectionMatrixAsOrtho2D(topleft.x(),bottomright.x(),topleft.y(),bottomright.y()); 
     454 
     455        while(!viewer.done()) 
     456        { 
     457            viewer.frame(); 
     458        } 
     459        return 0; 
     460    } 
     461    else 
     462    { 
     463        // create the windows and run the threads. 
     464        return viewer.run(); 
     465    } 
    771466}