Show
Ignore:
Timestamp:
08/22/14 21:00:53 (7 hours ago)
Author:
robert
Message:

Improved handling of setting of the depth of the UI.

Files:
1 modified

Legend:

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

    r13502 r13557  
    2323*/ 
    2424 
    25 #include <osg/Config> 
    26 #ifndef OSG_USE_DEPRECATED_GEOMETRY_METHODS  
    27 #define OSG_USE_DEPRECATED_GEOMETRY_METHODS 1 
    28 #endif 
    29  
    3025#include <osgDB/ReadFile> 
    3126#include <osgUtil/Optimizer> 
     
    5146    // wall constraint - can generate a wall at the coordinates of the constraint 
    5247public: 
    53 /** if you derive a class from DelaunayConstraint then you can create  
     48/** if you derive a class from DelaunayConstraint then you can create 
    5449*  a specific geometry creation routine. 
    5550    */ 
    5651    WallConstraint() : height(0), txxrepWall(10), txyrepWall(10)  { } 
    57      
     52 
    5853    /** or create a wall around the constraint area: */ 
    5954    virtual osg::Geometry * makeWallGeometry(void) const; 
    60      
     55 
    6156    /** for basic purposes, you can call these routines to make simple fill in geometries */ 
    6257    virtual osg::DrawArrays* makeWall(void ) const { // build a wall height high around the constraint 
     
    6459        return (new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,0,2*_line->size())); 
    6560    } 
    66      
    67      
     61 
     62 
    6863    virtual osg::Vec3Array *getWall(const float height) const; 
    6964    virtual osg::Vec2Array *getWallTexcoords(const float height) const; 
     
    7368        for (unsigned int ipr=0; ipr<getNumPrimitiveSets(); ipr++) { 
    7469            const osg::PrimitiveSet* prset=getPrimitiveSet(ipr); 
    75             if (prset->getMode()==osg::PrimitiveSet::LINE_LOOP ||  
     70            if (prset->getMode()==osg::PrimitiveSet::LINE_LOOP || 
    7671                prset->getMode()==osg::PrimitiveSet::LINE_STRIP) { // loops and walls 
    7772                // start with the last point on the loop 
     
    9489        return nrms.release(); 
    9590    } 
    96      
    97      
    98      
     91 
     92 
     93 
    9994    // geometry creation parameters 
    10095    void setWallTexrep(const float w,const float h) { txxrepWall=w;txyrepWall=h;} 
    101      
     96 
    10297    /** Wall Geometry will return with this texture applied: */ 
    10398    void setTexture(const char *tx) { texture=tx;} 
     
    112107    // areal constraint - general nonuniform field, forest, lake etc. 
    113108public: 
    114 /** if you derive a class from DelaunayConstraint then you can create  
     109/** if you derive a class from DelaunayConstraint then you can create 
    115110*  a specific geometry creation routine. 
    116111    */ 
    117112    ArealConstraint() : txxrepArea(10), txyrepArea(10),txxrepWall(10), txyrepWall(10) { } 
    118      
     113 
    119114    /** return a geometry that fills the constraint. 
    120115    */ 
    121     virtual osg::Geometry * makeAreal( osg::Vec3Array *points); 
    122      
     116    virtual deprecated_osg::Geometry * makeAreal( osg::Vec3Array *points); 
     117 
    123118    /** or create a wall around the constraint area: */ 
    124     virtual osg::Geometry * makeWallGeometry( osg::Vec3Array *points) ; 
    125      
     119    virtual deprecated_osg::Geometry * makeWallGeometry( osg::Vec3Array *points) ; 
     120 
    126121    /** for basic purposes, you can call these routines to make simple fill in geometries */ 
    127122    virtual osg::DrawArrays* makeWall(void ) const; 
     
    135130    virtual osg::Vec2Array *getCanopyTexcoords(const osg::Vec3Array *points) const; 
    136131    virtual osg::Vec3Array *getCanopyNormals(const osg::Vec3Array *points) const; 
    137      
     132 
    138133    // geometry creation parameters 
    139134    void setTexrep(const float w,const float h) { txxrepArea=w;txyrepArea=h;} 
     
    153148}; 
    154149 
    155 class LinearConstraint: public osgUtil::DelaunayConstraint {  
     150class LinearConstraint: public osgUtil::DelaunayConstraint { 
    156151/** forces edges of a "road" to fit triangles 
    157152*  if 2 roads cross, then the overlap will be replaced by a 'cross road' 
     
    159154public: 
    160155    LinearConstraint() : osgUtil::DelaunayConstraint(), txxrepAlong(10), txyrepAcross(10), width(2) { } 
    161      
     156 
    162157    /** geometry creation parameters */ 
    163158    /* Width of linear feature (eg road, railway) */ 
    164159    void setWidth(const float w) { width=w;} 
    165      
     160 
    166161    /** Texture repeat distance across linear (often equal to width) and along its length */ 
    167162    virtual void setTexrep(const float w,const float h) { txyrepAcross=h;txxrepAlong=w; } 
    168      
     163 
    169164    /** generate constant width around line - creates the area to be cut into the terrain. */ 
    170165    virtual void setVertices( osg::Vec3Array *lp, const float width); 
    171      
     166 
    172167    /** return a geometry that fills the constraint. 
    173168    */ 
    174     virtual osg::Geometry *makeGeometry(const osg::Vec3Array *points) ; 
    175      
     169    virtual deprecated_osg::Geometry *makeGeometry(const osg::Vec3Array *points) ; 
     170 
    176171    /** return normals array - flat shaded */ 
    177172    osg::Vec3Array* getNormals(const osg::Vec3Array *points); 
    178      
     173 
    179174    /** Roads apply a texture proportional to length along the road line. */ 
    180175    virtual osg::DrawArrays* makeRoad( ) const; 
    181176    virtual osg::Vec3Array *getRoadVertices() const; 
    182177    virtual osg::Vec2Array *getRoadTexcoords(const osg::Vec3Array *points) ; 
    183      
     178 
    184179    virtual osg::Vec3Array *getRoadNormals(const osg::Vec3Array *points) const; 
    185180    /** Geometry will return with this texture applied: */ 
    186181    void setTexture(const char *tx) { texture=tx;} 
    187      
     182 
    188183protected: 
    189184    osg::ref_ptr<osg::Vec2Array> _tcoords; 
     
    202197public: 
    203198    pyramid() : _side(100.) {} 
    204      
     199 
    205200    void setpos(const osg::Vec3 p, const float size) { _pos=p;_side=size;} 
    206      
     201 
    207202    virtual osg::Geometry * makeGeometry(void) const 
    208203        { 
    209204        // create pyramid geometry. Centre plus points around base 
    210205        const osg::Vec3Array *_line= dynamic_cast<const osg::Vec3Array*>(getVertexArray()); 
    211         osg::Geometry *gm=new osg::Geometry; 
     206        deprecated_osg::Geometry *gm=new deprecated_osg::Geometry; 
    212207        osg::Vec3Array *pts=new osg::Vec3Array; 
    213208        osg::Vec3Array *norms=new osg::Vec3Array; 
    214209        osg::Vec2Array *tcoords=new osg::Vec2Array; 
    215210        int ip; 
    216          
     211 
    217212        pts->push_back(_pos+osg::Vec3(0,0,_side)*0.5); 
    218213        for (ip=0; ip<4; ip++) { 
     
    224219            norms->push_back(nrm); 
    225220        } 
    226          
    227         gm->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE); 
     221 
     222        gm->setNormalBinding(deprecated_osg::Geometry::BIND_PER_PRIMITIVE); 
    228223        gm->setVertexArray(pts); 
    229224        osg::StateSet *dstate=   gm->getOrCreateStateSet(  ); 
    230225        dstate->setMode( GL_LIGHTING, osg::StateAttribute::ON ); 
    231          
     226 
    232227        osg::Image* image = osgDB::readImageFile("Images/Brick-Std-Orange.TGA"); 
    233228        if (image) 
     
    289284{ // add a string reporting the type of winding rule tessellation applied 
    290285    osg::Geode* geode = new osg::Geode(); 
    291      
     286 
    292287    std::string timesFont("fonts/arial.ttf"); 
    293      
     288 
    294289    // turn lighting off for the text and disable depth test to ensure its always ontop. 
    295290    osg::StateSet* stateset = geode->getOrCreateStateSet(); 
    296291    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF); 
    297      
    298     // Disable depth test, and make sure that the hud is drawn after everything  
     292 
     293    // Disable depth test, and make sure that the hud is drawn after everything 
    299294    // else so that it always appears ontop. 
    300295    stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF); 
    301296    stateset->setRenderBinDetails(11,"RenderBin"); 
    302      
     297 
    303298    osg::Vec3 position(50.0f,900.0f,0.0f); 
    304299    osg::Vec3 delta(0.0f,-35.0f,0.0f); 
    305      
     300 
    306301    { 
    307302        osgText::Text* text = new  osgText::Text; 
     
    309304        std::ostringstream cue; 
    310305        cue<<"Delaunay triangulation with constraints level "<<ndcs <<"\n"<< what; 
    311          
     306 
    312307        text->setFont(timesFont); 
    313308        text->setPosition(position); 
     
    316311        position += delta*(ndcs+2); 
    317312 
    318 #if 0         
     313#if 0 
    319314        text = new  osgText::Text; 
    320315        geode->addDrawable( text ); 
    321          
     316 
    322317        text->setFont(timesFont); 
    323318        text->setPosition(position); 
     
    325320        text->setColor(osg::Vec4(1.0,1.0,0.8,1.0)); 
    326321        position += delta; 
    327 #endif         
    328     }     
     322#endif 
     323    } 
    329324    { 
    330325        osgText::Text* text = new  osgText::Text; 
    331326        geode->addDrawable( text ); 
    332          
     327 
    333328        text->setFont(timesFont); 
    334329        text->setPosition(position); 
    335330        text->setText("Press 'n' to add another constraint."); 
    336          
    337     }     
    338      
     331 
     332    } 
     333 
    339334    // create the hud. 
    340335    osg::MatrixTransform* modelview_abs = new osg::MatrixTransform; 
     
    342337    modelview_abs->setMatrix(osg::Matrix::identity()); 
    343338    modelview_abs->addChild(geode); 
    344      
     339 
    345340    osg::Projection* projection = new osg::Projection; 
    346341    projection->setMatrix(osg::Matrix::ortho2D(0,1280,0,1024)); 
    347342    projection->addChild(modelview_abs); 
    348      
     343 
    349344    return projection; 
    350      
     345 
    351346} 
    352347osg::Group *makedelaunay(const int ndcs) 
     
    357352    osg::ref_ptr<osgUtil::DelaunayTriangulator> trig=new osgUtil::DelaunayTriangulator(); 
    358353    osg::StateSet *stateset=geode->getOrCreateStateSet(); 
    359      
     354 
    360355    osg::Vec3Array *points=new osg::Vec3Array; 
    361      
     356 
    362357    osg::Image* image = osgDB::readImageFile("Images/blueFlowers.png"); 
    363358    if (image) 
     
    369364        stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON); 
    370365    } 
    371      
     366 
    372367    geode->setStateSet( stateset ); 
    373368    unsigned int i; 
    374      
     369 
    375370    int eod=0; 
    376371    while (eod>=0) { 
     
    406401        dc->setVertexArray(bounds); 
    407402        dc->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP,0,nmax) ); 
    408          
     403 
    409404        trig->addInputConstraint(dc.get()); 
    410405        what << nmax << " point simple constraint\n"; 
     
    432427            dc->setVertexArray(bounds); 
    433428            dc->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP,0,12) ); 
    434              
     429 
    435430            trig->addInputConstraint(dc.get()); 
    436431            what << 12 << " point closed loop"; 
    437              
     432 
    438433            if (ndcs>2) { 
    439434                wc=new WallConstraint; // This example does not remove the interior 
     
    453448                what << " with interior removed\n"; 
    454449                what << 5 << " point wall derived constraint\n"; 
    455                  
     450 
    456451                if (ndcs>3) { 
    457452                    // add a removed area and replace it with a different texture 
     
    467462                    trig->addInputConstraint(dc2.get()); 
    468463                    what << 18 << " point area replaced\n"; 
    469                      
     464 
    470465                    if (ndcs>4) { 
    471466                        dc3=new LinearConstraint; 
     
    501496                            if (ndcs==6) trig->addInputConstraint(forest.get()); 
    502497                            what << 12 << " point forest constraint\n"; 
    503                              
     498 
    504499                            if (ndcs>6) { // add roads that intersect forest 
    505500                                osg::ref_ptr<osgUtil::DelaunayConstraint> forestplus=new osgUtil::DelaunayConstraint; 
     
    611606    } // ndcs>0 
    612607    trig->setInputPointArray(points); 
    613      
     608 
    614609    /** NB you need to supply a vec3 array for the triangulator to calculate normals into */ 
    615610    osg::Vec3Array *norms=new osg::Vec3Array; 
    616611    trig->setOutputNormalArray(norms); 
    617      
     612 
    618613    trig->triangulate(); 
    619614    osg::notify(osg::WARN) << " End of trig\n " <<std::endl; 
    620      
    621     // Calculate the texture coordinates after triangulation as  
     615 
     616    // Calculate the texture coordinates after triangulation as 
    622617    //the points may get disordered by the triangulate function 
    623     osg::ref_ptr<osg::Geometry> gm=new osg::Geometry; 
     618    osg::ref_ptr<deprecated_osg::Geometry> gm=new deprecated_osg::Geometry; 
    624619    gm->setVertexArray(points); // points may have been modified in order by triangulation. 
    625620    /** calculate texture coords for terrain points */ 
     
    635630    gm->addPrimitiveSet(trig->getTriangles()); 
    636631    gm->setNormalArray(trig->getOutputNormalArray()); 
    637     gm->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE); 
     632    gm->setNormalBinding(deprecated_osg::Geometry::BIND_PER_PRIMITIVE); 
    638633    geode->addDrawable(gm.get()); 
    639634    if (ndcs>0) { 
     
    642637            geode->addDrawable((*itr)->makeGeometry()); // this fills the holes of each pyramid with geometry 
    643638        } 
    644          
     639 
    645640        if (ndcs>2) { 
    646641            trig->removeInternalTriangles(dc.get()); 
    647              
     642 
    648643            wc->setTexture("Images/Brick-Norman-Brown.TGA"); // wall looks like brick 
    649644            geode->addDrawable(wc->makeWallGeometry()); // this creates wall at wc drawarrays 
     
    653648                dc2->setTexture("Images/purpleFlowers.png"); 
    654649                geode->addDrawable(dc2->makeAreal(arpts.get())); // this creates fill in geometry 
    655                  
     650 
    656651                if (ndcs>4) { // a simple "road" 
    657652                    trig->removeInternalTriangles(dc3.get()); 
     
    659654                    dc3->setTexrep(40,9.5); // texture is repeated at this frequency 
    660655                    geode->addDrawable(dc3->makeGeometry(points)); // this creates road geometry 
    661                      
     656 
    662657                    if (ndcs>5) { 
    663658                        if (ndcs>6) { //  road & forest overlap - order of removal is important 
     
    667662                        } 
    668663                        trig->removeInternalTriangles(forest.get()); 
    669                         forest->setTexture("Images/forestRoof.png");  
     664                        forest->setTexture("Images/forestRoof.png"); 
    670665                        osg::ref_ptr<osg::Vec3Array> locpts=forest->getPoints(points); 
    671666                        geode->addDrawable(forest->makeAreal(locpts.get())); 
    672667 
    673                         forest->setWallTexture("Images/forestWall.png");  
     668                        forest->setWallTexture("Images/forestWall.png"); 
    674669                        geode->addDrawable(forest->makeWallGeometry(locpts.get()) ); 
    675670                        for (osg::Vec3Array::iterator vit=(*locpts).begin(); vit!=(*locpts).end(); vit++) { 
     
    719714{ // extra event handler traps 'n' key to re-triangulate the basic terrain. 
    720715public: 
    721      
     716 
    722717    KeyboardEventHandler(osgViewer::Viewer &vr): 
    723718      viewer(vr), iview(0) {} 
    724        
     719 
    725720      virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&) 
    726721      { 
     
    744739          return false; 
    745740      } 
    746        
     741 
    747742      osgViewer::Viewer &viewer; 
    748743      int iview; 
     
    792787            const osg::Vec3 curp=(*vertices)[prset->index (0)]; 
    793788            circumference+=(curp-prevp).length(); 
    794              
     789 
    795790            int nround=(int)(circumference/txxrepWall); 
    796791            if (nround<1) nround=1; // at least one repeat. 
    797792            texrepRound=circumference/nround; 
    798              
     793 
    799794            float ds=0; 
    800795            prevp=(*vertices)[prset->index (prset->getNumIndices()-1)]; 
     
    815810            } 
    816811        } // per primitiveset 
    817          
     812 
    818813    } 
    819814    return tcoords; 
     
    844839    gm->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); 
    845840    gm->setNormalArray(getWallNormals()); // this creates normals to walls 
    846      
     841 
    847842    return gm.release(); 
    848843} 
     
    919914            const osg::Vec3 curp=(*vertices)[prset->index (0)]; 
    920915            circumference+=(curp-prevp).length(); 
    921              
     916 
    922917            int nround=(int)(circumference/txxrepWall); 
    923918            if (nround<1) nround=1; // at least one repeat. 
    924919            texrepRound=circumference/nround; 
    925              
     920 
    926921            float ds=0; 
    927922            prevp=(*vertices)[prset->index (prset->getNumIndices()-1)]; 
     
    994989} 
    995990 
    996 osg::Geometry *ArealConstraint::makeWallGeometry( osg::Vec3Array *pt)  
     991deprecated_osg::Geometry *ArealConstraint::makeWallGeometry( osg::Vec3Array *pt) 
    997992{ 
    998     osg::ref_ptr<osg::Geometry> gm=new osg::Geometry; // the wall 
    999     osg::ref_ptr<osg::Geometry> edges=new osg::Geometry; // edges of bounds 
     993    osg::ref_ptr<deprecated_osg::Geometry> gm=new deprecated_osg::Geometry; // the wall 
     994    osg::ref_ptr<deprecated_osg::Geometry> edges=new deprecated_osg::Geometry; // edges of bounds 
    1000995    edges->setVertexArray(pt); 
    1001996    osg::DrawElementsUInt *trgeom=getTriangles(); 
    1002997    edges->addPrimitiveSet(trgeom); 
    1003      
     998 
    1004999    osg::ref_ptr<osgUtil::Tessellator> tscx=new osgUtil::Tessellator; // this assembles all the constraints 
    10051000    tscx->setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY); 
    10061001    tscx->setBoundaryOnly(true); 
    1007     tscx->setWindingType( osgUtil::Tessellator::TESS_WINDING_NONZERO);  
     1002    tscx->setWindingType( osgUtil::Tessellator::TESS_WINDING_NONZERO); 
    10081003    //  find all edges. 
    10091004    const osg::Vec3Array *points=dynamic_cast<osg::Vec3Array*>(getVertexArray()); 
    1010      
     1005 
    10111006    tscx->retessellatePolygons(*(edges)); // find all edges 
    1012      
     1007 
    10131008    if (walltexture!="") { 
    10141009        osg::Image* image = osgDB::readImageFile(walltexture.c_str()); 
     
    10531048        } 
    10541049    } 
    1055      
     1050 
    10561051    return gm.release(); 
    10571052} 
    10581053 
    10591054 
    1060 osg::Geometry * ArealConstraint::makeAreal( osg::Vec3Array *points)  
     1055deprecated_osg::Geometry * ArealConstraint::makeAreal( osg::Vec3Array *points) 
    10611056{ 
    1062     osg::ref_ptr<osg::Geometry> gm; // the fill in area 
     1057    osg::ref_ptr<deprecated_osg::Geometry> gm; // the fill in area 
    10631058    if (_interiorTris.size()>0) { 
    1064         gm =new osg::Geometry; // the forest roof 
     1059        gm =new deprecated_osg::Geometry; // the forest roof 
    10651060        gm->setVertexArray(points); 
    10661061        osg::DrawElementsUInt *trgeom=getTriangles(); 
    10671062        gm->addPrimitiveSet(trgeom); 
    10681063        gm->setNormalArray(getCanopyNormals(points)); 
    1069         gm->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE); 
     1064        gm->setNormalBinding(deprecated_osg::Geometry::BIND_PER_PRIMITIVE); 
    10701065        gm->setTexCoordArray(0,getCanopyTexcoords(points)); 
    10711066        osg::Image* image = osgDB::readImageFile(texture); 
     
    11001095        osg::Vec3 valong; 
    11011096        osg::Vec3 pos[2]; 
    1102          
     1097 
    11031098        if (i==0) { 
    11041099            valong=(*lp)[i+1]-(*lp)[i]; 
     
    11271122{ 
    11281123    return     new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,0,2*_midline->size()); 
    1129      
     1124 
    11301125} 
    11311126 
     
    12051200                } 
    12061201                ibm1=ib; 
    1207                 ib++;     
     1202                ib++; 
    12081203                pminus=(*vit); 
    12091204            } 
     
    12251220    return tcoords.release(); 
    12261221} 
    1227 osg::Vec3Array * LinearConstraint::getNormals(const osg::Vec3Array *points)  
     1222osg::Vec3Array * LinearConstraint::getNormals(const osg::Vec3Array *points) 
    12281223{ 
    12291224    osg::ref_ptr<osg::Vec3Array> norms=new osg::Vec3Array; 
     
    12391234} 
    12401235 
    1241 osg::Geometry * LinearConstraint::makeGeometry(const osg::Vec3Array *points)  
     1236deprecated_osg::Geometry * LinearConstraint::makeGeometry(const osg::Vec3Array *points) 
    12421237{ 
    1243     osg::ref_ptr<osg::Geometry> gm=new osg::Geometry; // the fill in road/railway 
     1238    osg::ref_ptr<deprecated_osg::Geometry> gm=new deprecated_osg::Geometry; // the fill in road/railway 
    12441239    if (_midline->size()>0) { 
    12451240        osg::ref_ptr<osg::Vec3Array> locpts=getPoints(points); 
     
    12641259        gm->setVertexArray(locpts.get()); 
    12651260        gm->setNormalArray(getNormals(locpts.get())); 
    1266         gm->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE); 
     1261        gm->setNormalBinding(deprecated_osg::Geometry::BIND_PER_PRIMITIVE); 
    12671262        gm->addPrimitiveSet(getTriangles()); 
    12681263    } 
    1269      
     1264 
    12701265    return gm.release(); 
    1271      
     1266 
    12721267} 
    12731268 
     
    12761271int main( int argc, char **argv ) 
    12771272{ 
    1278      
     1273 
    12791274    // use an ArgumentParser object to manage the program arguments. 
    12801275    osg::ArgumentParser arguments(&argc,argv); 
     
    12851280    // create the scene from internal specified terrain/constraints. 
    12861281    osg::ref_ptr<osg::Node> loadedModel = makedelaunay(0); 
    1287      
     1282 
    12881283    // if no model has been successfully loaded report failure. 
    1289     if (!loadedModel)  
     1284    if (!loadedModel) 
    12901285    { 
    12911286        std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl; 
    12921287        return 1; 
    12931288    } 
    1294      
     1289 
    12951290    // optimize the scene graph, remove redundant nodes and state etc. 
    12961291    osgUtil::Optimizer optimizer; 
    12971292    optimizer.optimize(loadedModel.get()); 
    1298      
     1293 
    12991294    // pass the loaded scene graph to the viewer. 
    13001295    viewer.setSceneData(loadedModel.get()); 
    1301      
     1296 
    13021297    // copied from osgtessealte.cpp 
    13031298    // add event handler for keyboard 'n' to retriangulate 
    13041299    viewer.addEventHandler(new KeyboardEventHandler(viewer)); 
    1305      
     1300 
    13061301    return viewer.run(); 
    13071302}