root/OpenSceneGraph/trunk/examples/osgocclusionquery/osgocclusionquery.cpp @ 13223

Revision 12528, 22.9 kB (checked in by robert, 4 years ago)

Improved the handling of command line parameters

  • Property svn:eol-style set to native
Line 
1/* OpenSceneGraph example, osganimate.
2*
3*  Permission is hereby granted, free of charge, to any person obtaining a copy
4*  of this software and associated documentation files (the "Software"), to deal
5*  in the Software without restriction, including without limitation the rights
6*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7*  copies of the Software, and to permit persons to whom the Software is
8*  furnished to do so, subject to the following conditions:
9*
10*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16*  THE SOFTWARE.
17*/
18
19// This exampl demonstrates use of OcclusionQueryNode.
20//
21// In general, you use OcclusionQueryNode by simply attaching a subgraph
22// or subgraphs as children, and it performs an OpenGL oclusion query
23// to determine whether to draw the subgraphs or not.
24//
25// You can manually insert OcclusionQueryNodes at strategic locations
26// in your scene graph, or you can write a NodeVisitor to insert them
27// automatically, as this example shows.
28//
29// Run this example with no command line arguments, and it creates
30// a "stock scene" to show how OcclusionQueryNode can be used.
31//
32// Or, run this example with a model on the command line, and the
33// example uses a NodeVisitor to try to find worthwhile locations
34// for OcclusionQueryNodes in your the scene graph.
35
36
37
38#include <osg/NodeVisitor>
39#include <osg/Geode>
40#include <osg/Geometry>
41#include <osg/StateSet>
42#include <osg/StateAttribute>
43#include <osg/PolygonMode>
44#include <osg/ColorMask>
45#include <osg/PolygonOffset>
46#include <osg/Depth>
47
48#include <osgDB/ReadFile>
49#include <osgDB/WriteFile>
50
51#include <osgUtil/Optimizer>
52
53#include <osgViewer/Viewer>
54#include <osgViewer/ViewerEventHandlers>
55
56#include <osgGA/StateSetManipulator>
57
58#include <osg/OcclusionQueryNode>
59
60#include <iostream>
61#include <sstream>
62
63
64// NodeVisitors and utility functions for OcclusionQueryNode
65
66// Use this visitor to insert OcclusionQueryNodes (OQNs) in the
67//   visited subgraph. Only one OQN will test any particular node
68//   (no nesting). See also OcclusionQueryNonFlatVisitor.
69class OcclusionQueryVisitor : public osg::NodeVisitor
70{
71public:
72    OcclusionQueryVisitor();
73    virtual ~OcclusionQueryVisitor();
74
75    // Specify the vertex count threshold for performing occlusion
76    //   query tests. Nodes in the scene graph whose total child geometry
77    //   contains fewer vertices than the specified threshold will
78    //   never be tested, just drawn. (In fact, they will br treated as
79    //   potential occluders and rendered first in front-to-back order.)
80    void setOccluderThreshold( int vertices );
81    int getOccluderThreshold() const;
82
83    virtual void apply( osg::OcclusionQueryNode& oqn );
84    virtual void apply( osg::Group& group );
85    virtual void apply( osg::Geode& geode );
86
87protected:
88    void addOQN( osg::Node& node );
89
90    // When an OQR creates all OQNs and each OQN shares the same OQC,
91    //   these methods are used to uniquely name all OQNs. Handy
92    //   for debugging.
93    std::string getNextOQNName();
94    int getNameIdx() const { return _nameIdx; }
95
96    osg::ref_ptr<osg::StateSet> _state;
97    osg::ref_ptr<osg::StateSet> _debugState;
98
99    unsigned int _nameIdx;
100
101    int _occluderThreshold;
102};
103
104// Find all OQNs in the visited scene graph and set their visibility threshold.
105class VisibilityThresholdVisitor : public osg::NodeVisitor
106{
107public:
108    VisibilityThresholdVisitor( unsigned int threshold=500 )
109      : osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ),
110        _visThreshold( threshold ) {}
111    virtual ~VisibilityThresholdVisitor() {}
112
113    virtual void apply( osg::OcclusionQueryNode& oqn );
114
115protected:
116    unsigned int _visThreshold;
117};
118
119// Find all OQNs in the visited scene graph and set the number of frames
120//   between queries.
121class QueryFrameCountVisitor : public osg::NodeVisitor
122{
123public:
124    QueryFrameCountVisitor( int count=5 )
125      : osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ),
126        _count( count ) {}
127    virtual ~QueryFrameCountVisitor() {}
128
129    virtual void apply( osg::OcclusionQueryNode& oqn );
130
131protected:
132    unsigned int _count;
133};
134
135// Find all OQNs in the visited scene graph and enable or disable queries..
136class EnableQueryVisitor : public osg::NodeVisitor
137{
138public:
139    EnableQueryVisitor( bool enable=true )
140      : osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ),
141        _enabled( enable ) {}
142    virtual ~EnableQueryVisitor() {}
143
144    virtual void apply( osg::OcclusionQueryNode& oqn );
145
146protected:
147    bool _enabled;
148};
149
150// Find all OQNs in the visited scene graph and enable or disable the
151//   debug bounding volume display.
152class DebugDisplayVisitor : public osg::NodeVisitor
153{
154public:
155    DebugDisplayVisitor( bool debug=true )
156      : osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ),
157        _debug( debug ) {}
158    virtual ~DebugDisplayVisitor() {}
159
160    virtual void apply( osg::OcclusionQueryNode& oqn );
161
162protected:
163    bool _debug;
164};
165
166// Remove all OQNs from the visited scene graph.
167class RemoveOcclusionQueryVisitor : public osg::NodeVisitor
168{
169public:
170    RemoveOcclusionQueryVisitor();
171    virtual ~RemoveOcclusionQueryVisitor();
172
173    virtual void apply( osg::OcclusionQueryNode& oqn );
174
175protected:
176};
177
178// Gather statistics about OQN performance in the visited scene graph.
179class StatisticsVisitor : public osg::NodeVisitor
180{
181public:
182    StatisticsVisitor( osg::NodeVisitor::TraversalMode mode=osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN );
183    virtual ~StatisticsVisitor();
184
185    virtual void apply( osg::OcclusionQueryNode& oqn );
186
187    void reset();
188    unsigned int getNumOQNs() const;
189    unsigned int getNumPassed() const;
190
191protected:
192    unsigned int _numOQNs;
193    unsigned int _numPassed;
194};
195
196
197unsigned int countGeometryVertices( osg::Geometry* geom )
198{
199    if (!geom->getVertexArray())
200        return 0;
201
202    // TBD This will eventually iterate over the PrimitiveSets and total the
203    //   number of vertices actually used. But for now, it just returns the
204    //   size of the vertex array.
205
206    return geom->getVertexArray()->getNumElements();
207}
208
209class VertexCounter : public osg::NodeVisitor
210{
211public:
212    VertexCounter( int limit )
213      : osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ),
214        _limit( limit ),
215        _total( 0 ) {}
216    ~VertexCounter() {}
217
218    int getTotal() { return _total; }
219    bool exceeded() const { return _total > _limit; }
220    void reset() { _total = 0; }
221
222    virtual void apply( osg::Node& node )
223    {
224        // Check for early abort. If out total already exceeds the
225        //   max number of vertices, no need to traverse further.
226        if (exceeded())
227            return;
228        traverse( node );
229    }
230
231    virtual void apply( osg::Geode& geode )
232    {
233        // Possible early abort.
234        if (exceeded())
235            return;
236
237        unsigned int i;
238        for( i = 0; i < geode.getNumDrawables(); i++ )
239        {
240            osg::Geometry* geom = dynamic_cast<osg::Geometry *>(geode.getDrawable(i));
241            if( !geom )
242                continue;
243
244            _total += countGeometryVertices( geom );
245
246            if (_total > _limit)
247                break;
248        }
249    }
250
251protected:
252    int _limit;
253    int _total;
254};
255
256
257
258OcclusionQueryVisitor::OcclusionQueryVisitor()
259  : osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ),
260    _nameIdx( 0 ),
261    _occluderThreshold( 5000 )
262{
263    // Create a dummy OcclusionQueryNode just so we can get its state.
264    // We'll then share that state between all OQNs we add to the visited scene graph.
265    osg::ref_ptr<osg::OcclusionQueryNode> oqn = new osg::OcclusionQueryNode;
266
267    _state = oqn->getQueryStateSet();
268    _debugState = oqn->getDebugStateSet();
269}
270
271OcclusionQueryVisitor::~OcclusionQueryVisitor()
272{
273    osg::notify( osg::INFO ) <<
274        "osgOQ: OcclusionQueryVisitor: Added " << getNameIdx() <<
275        " OQNodes." << std::endl;
276}
277
278void
279OcclusionQueryVisitor::setOccluderThreshold( int vertices )
280{
281    _occluderThreshold = vertices;
282}
283int
284OcclusionQueryVisitor::getOccluderThreshold() const
285{
286    return _occluderThreshold;
287}
288
289void
290OcclusionQueryVisitor::apply( osg::OcclusionQueryNode& oqn )
291{
292    // A subgraph is already under osgOQ control.
293    // Don't traverse further.
294    return;
295}
296
297void
298OcclusionQueryVisitor::apply( osg::Group& group )
299{
300    if (group.getNumParents() == 0)
301    {
302        // Can't add an OQN above a root node.
303        traverse( group );
304        return;
305    }
306
307    int preTraverseOQNCount = getNameIdx();
308    traverse( group );
309
310    if (getNameIdx() > preTraverseOQNCount)
311        // A least one OQN was added below the current node.
312        //   Don't add one here to avoid hierarchical nesting.
313        return;
314
315    // There are no OQNs below this group. If the vertex
316    //   count exceeds the threshold, add an OQN here.
317    addOQN( group );
318}
319
320void
321OcclusionQueryVisitor::apply( osg::Geode& geode )
322{
323    if (geode.getNumParents() == 0)
324    {
325        // Can't add an OQN above a root node.
326        traverse( geode );
327        return;
328    }
329
330    addOQN( geode );
331}
332
333void
334OcclusionQueryVisitor::addOQN( osg::Node& node )
335{
336    VertexCounter vc( _occluderThreshold );
337    node.accept( vc );
338    if (vc.exceeded())
339    {
340        // Insert OQN(s) above this node.
341        unsigned int np = node.getNumParents();
342        while (np--)
343        {
344            osg::Group* parent = dynamic_cast<osg::Group*>( node.getParent( np ) );
345            if (parent != NULL)
346            {
347                osg::ref_ptr<osg::OcclusionQueryNode> oqn = new osg::OcclusionQueryNode();
348                oqn->addChild( &node );
349                parent->replaceChild( &node, oqn.get() );
350
351                oqn->setName( getNextOQNName() );
352                // Set all OQNs to use the same query StateSets (instead of multiple copies
353                //   of the same StateSet) for efficiency.
354                oqn->setQueryStateSet( _state.get() );
355                oqn->setDebugStateSet( _debugState.get() );
356            }
357        }
358    }
359}
360
361std::string
362OcclusionQueryVisitor::getNextOQNName()
363{
364    std::ostringstream ostr;
365    ostr << "OQNode_" << _nameIdx++;
366    return ostr.str();
367}
368
369
370
371
372//
373void
374VisibilityThresholdVisitor::apply( osg::OcclusionQueryNode& oqn )
375{
376    oqn.setVisibilityThreshold( _visThreshold );
377
378    traverse( oqn );
379}
380
381void
382QueryFrameCountVisitor::apply( osg::OcclusionQueryNode& oqn )
383{
384    oqn.setQueryFrameCount( _count );
385
386    traverse( oqn );
387}
388
389void
390EnableQueryVisitor::apply( osg::OcclusionQueryNode& oqn )
391{
392    oqn.setQueriesEnabled( _enabled );
393
394    traverse( oqn );
395}
396
397
398void
399DebugDisplayVisitor::apply( osg::OcclusionQueryNode& oqn )
400{
401    oqn.setDebugDisplay( _debug );
402
403    traverse( oqn );
404}
405
406
407RemoveOcclusionQueryVisitor::RemoveOcclusionQueryVisitor()
408  : osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN )
409{
410}
411
412RemoveOcclusionQueryVisitor::~RemoveOcclusionQueryVisitor()
413{
414}
415
416void
417RemoveOcclusionQueryVisitor::apply( osg::OcclusionQueryNode& oqn )
418{
419    if (oqn.getNumParents() == 0)
420    {
421        // Even if this is an OQN, can't delete it because it's the root.
422        traverse( oqn );
423        return;
424    }
425
426    osg::ref_ptr<osg::OcclusionQueryNode> oqnPtr = &oqn;
427
428    unsigned int np = oqn.getNumParents();
429    while (np--)
430    {
431        osg::Group* parent = dynamic_cast<osg::Group*>( oqn.getParent( np ) );
432        if (parent != NULL)
433        {
434            // Remove OQN from parent.
435            parent->removeChild( oqnPtr.get() );
436
437            // Add OQN's children to parent.
438            unsigned int nc = oqn.getNumChildren();
439            while (nc--)
440                parent->addChild( oqn.getChild( nc ) );
441        }
442    }
443}
444
445
446
447StatisticsVisitor::StatisticsVisitor( osg::NodeVisitor::TraversalMode mode )
448  : osg::NodeVisitor( mode ),
449    _numOQNs( 0 ),
450    _numPassed( 0 )
451{
452}
453
454StatisticsVisitor::~StatisticsVisitor()
455{
456}
457
458void
459StatisticsVisitor::apply( osg::OcclusionQueryNode& oqn )
460{
461    _numOQNs++;
462    if (oqn.getPassed())
463        _numPassed++;
464
465    traverse( oqn );
466}
467
468void
469StatisticsVisitor::reset()
470{
471    _numOQNs = _numPassed = 0;
472}
473
474unsigned int
475StatisticsVisitor::getNumOQNs() const
476{
477    return _numOQNs;
478}
479unsigned int
480StatisticsVisitor::getNumPassed() const
481{
482    return _numPassed;
483}
484
485// End NodeVisitors
486
487
488
489// KetHandler --
490// Allow user to do interesting things with an
491// OcclusionQueryNode-enabled scene graph at run time.
492class KeyHandler : public osgGA::GUIEventHandler
493{
494public:
495    KeyHandler( osg::Node& node )
496      : _node( node ),
497        _enable( true ),
498        _debug( false )
499    {}
500
501    bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& )
502    {
503        switch( ea.getEventType() )
504        {
505            case(osgGA::GUIEventAdapter::KEYUP):
506            {
507                if (ea.getKey()==osgGA::GUIEventAdapter::KEY_F6)
508                {
509                    // F6 -- Toggle osgOQ testing.
510                    _enable = !_enable;
511                    EnableQueryVisitor eqv( _enable );
512                    _node.accept( eqv );
513                    return true;
514                }
515                else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_F7)
516                {
517                    // F7 -- Toggle display of OQ test bounding volumes
518                    _debug = !_debug;
519                    DebugDisplayVisitor ddv( _debug );
520                    _node.accept( ddv );
521                    return true;
522                }
523                else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_F8)
524                {
525                    // F8 -- Gether stats and display
526                    StatisticsVisitor sv;
527                    _node.accept( sv );
528                    std::cout << "osgOQ: Stats: numOQNs " << sv.getNumOQNs() << ", numPased " << sv.getNumPassed() << std::endl;
529                    return true;
530                }
531                else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_F9)
532                {
533                    // F9 -- Remove all OcclusionQueryNodes
534                    RemoveOcclusionQueryVisitor roqv;
535                    _node.accept( roqv );
536                    return true;
537                }
538                else if (ea.getKey()=='o')
539                {
540                    if (osgDB::writeNodeFile( _node, "saved_model.osgt" ))
541                        osg::notify( osg::ALWAYS ) << "osgOQ: Wrote scene graph to \"saved_model.osgt\"" << std::endl;
542                    else
543                        osg::notify( osg::ALWAYS ) << "osgOQ: Wrote failed for \"saved_model.osgt\"" << std::endl;
544                    return true;
545                }
546                return false;
547            }
548            default:
549                break;
550        }
551        return false;
552    }
553
554    osg::Node& _node;
555
556    bool _enable, _debug;
557};
558
559// Create a cube with one side missing. This makes a great simple occluder.
560osg::ref_ptr<osg::Node>
561createBox()
562{
563    osg::ref_ptr<osg::Geode> box = new osg::Geode;
564
565    osg::StateSet* state = box->getOrCreateStateSet();
566    osg::PolygonMode* pm = new osg::PolygonMode(
567        osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL );
568    state->setAttributeAndModes( pm,
569        osg::StateAttribute::ON | osg::StateAttribute::PROTECTED );
570
571    osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
572    osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;
573    geom->setVertexArray( v.get() );
574
575    {
576        const float x( 0.f );
577        const float y( 0.f );
578        const float z( 0.f );
579        const float r( 1.1f );
580
581        v->push_back( osg::Vec3( x-r, y-r, z-r ) ); //left -X
582        v->push_back( osg::Vec3( x-r, y-r, z+r ) );
583        v->push_back( osg::Vec3( x-r, y+r, z+r ) );
584        v->push_back( osg::Vec3( x-r, y+r, z-r ) );
585
586        v->push_back( osg::Vec3( x+r, y-r, z+r ) ); //right +X
587        v->push_back( osg::Vec3( x+r, y-r, z-r ) );
588        v->push_back( osg::Vec3( x+r, y+r, z-r ) );
589        v->push_back( osg::Vec3( x+r, y+r, z+r ) );
590
591        v->push_back( osg::Vec3( x-r, y-r, z-r ) ); // bottom -Z
592        v->push_back( osg::Vec3( x-r, y+r, z-r ) );
593        v->push_back( osg::Vec3( x+r, y+r, z-r ) );
594        v->push_back( osg::Vec3( x+r, y-r, z-r ) );
595
596        v->push_back( osg::Vec3( x-r, y-r, z+r ) ); // top +Z
597        v->push_back( osg::Vec3( x+r, y-r, z+r ) );
598        v->push_back( osg::Vec3( x+r, y+r, z+r ) );
599        v->push_back( osg::Vec3( x-r, y+r, z+r ) );
600
601        v->push_back( osg::Vec3( x-r, y+r, z-r ) ); // back +Y
602        v->push_back( osg::Vec3( x-r, y+r, z+r ) );
603        v->push_back( osg::Vec3( x+r, y+r, z+r ) );
604        v->push_back( osg::Vec3( x+r, y+r, z-r ) );
605    }
606
607    osg::ref_ptr<osg::Vec4Array> c = new osg::Vec4Array;
608    geom->setColorArray( c.get() );
609    geom->setColorBinding( osg::Geometry::BIND_OVERALL );
610    c->push_back( osg::Vec4( 0.f, 1.f, 1.f, 1.f ) );
611
612    osg::ref_ptr<osg::Vec3Array> n = new osg::Vec3Array;
613    geom->setNormalArray( n.get() );
614    geom->setNormalBinding( osg::Geometry::BIND_PER_PRIMITIVE );
615    n->push_back( osg::Vec3( -1.f, 0.f, 0.f ) );
616    n->push_back( osg::Vec3( 1.f, 0.f, 0.f ) );
617    n->push_back( osg::Vec3( 0.f, 0.f, -1.f ) );
618    n->push_back( osg::Vec3( 0.f, 0.f, 1.f ) );
619    n->push_back( osg::Vec3( 0.f, 1.f, 0.f ) );
620
621    geom->addPrimitiveSet( new osg::DrawArrays( GL_QUADS, 0, 20 ) );
622    box->addDrawable( geom.get() );
623
624    return box.get();
625}
626
627// Make a Geometry that renders slow intentionally.
628// To make sure it renders slow, we do the following:
629//  * Disable display lists
630//  * Force glBegin/glEnd slow path
631//  * Lots of vertices and color data per vertex
632//  * No vertex sharing
633//  * Draw the triangles as wireframe
634osg::ref_ptr<osg::Node>
635createRandomTriangles( unsigned int num )
636{
637    osg::ref_ptr<osg::Geode> tris = new osg::Geode;
638
639    osg::StateSet* ss = tris->getOrCreateStateSet();
640
641    // Force wireframe. Many gfx cards handle this poorly.
642    osg::PolygonMode* pm = new osg::PolygonMode(
643        osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE );
644    ss->setAttributeAndModes( pm, osg::StateAttribute::ON |
645        osg::StateAttribute::PROTECTED);
646    ss->setMode( GL_LIGHTING, osg::StateAttribute::OFF |
647        osg::StateAttribute::PROTECTED);
648
649    osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
650    // Disable display lists to decrease performance.
651    geom->setUseDisplayList( false );
652
653    osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;
654    geom->setVertexArray( v.get() );
655    v->resize( num*3 );
656
657    unsigned int i;
658    srand( 0 );
659#define RAND_NEG1_TO_1 ( ((rand()%20)-10)*.1 )
660    for (i=0; i<num; i++)
661    {
662        osg::Vec3& v0 = (*v)[ i*3+0 ];
663        osg::Vec3& v1 = (*v)[ i*3+1 ];
664        osg::Vec3& v2 = (*v)[ i*3+2 ];
665        v0 = osg::Vec3( RAND_NEG1_TO_1, RAND_NEG1_TO_1, RAND_NEG1_TO_1 );
666        v1 = osg::Vec3( RAND_NEG1_TO_1, RAND_NEG1_TO_1, RAND_NEG1_TO_1 );
667        v2 = osg::Vec3( RAND_NEG1_TO_1, RAND_NEG1_TO_1, RAND_NEG1_TO_1 );
668    }
669
670    osg::ref_ptr<osg::Vec4Array> c = new osg::Vec4Array;
671    geom->setColorArray( c.get() );
672    // Bind per primitive to force slow glBegin/glEnd path.
673    geom->setColorBinding( osg::Geometry::BIND_PER_PRIMITIVE );
674    c->resize( num );
675
676#define RAND_0_TO_1 ( (rand()%10)*.1 )
677    for (i=0; i<num; i++)
678    {
679        osg::Vec4& c0 = (*c)[ i ];
680        c0 = osg::Vec4( RAND_0_TO_1, RAND_0_TO_1, RAND_0_TO_1, 1. );
681    }
682
683    geom->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLES, 0, num*3 ) );
684    tris->addDrawable( geom.get() );
685
686    return tris.get();
687}
688
689// Create the stock scene:
690// Top level Group
691//   Geode (simple occluder
692//   OcclusionQueryNode
693//     Geode with complex, slow geometry.
694osg::ref_ptr<osg::Node>
695createStockScene()
696{
697    // Create a simple box occluder
698    osg::ref_ptr<osg::Group> root = new osg::Group();
699    root->addChild( createBox().get() );
700
701    // Create a complex mess of triangles as a child below an
702    //   OcclusionQueryNode. The OQN will ensure that the
703    //   subgraph isn't rendered when it's not visible.
704    osg::ref_ptr<osg::OcclusionQueryNode> oqn = new osg::OcclusionQueryNode;
705    oqn->addChild( createRandomTriangles( 20000 ).get() );
706    root->addChild( oqn.get() );
707
708    return root.get();
709}
710
711
712int main(int argc, char** argv)
713{
714    // use an ArgumentParser object to manage the program arguments.
715    osg::ArgumentParser arguments(&argc,argv);
716
717    arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
718    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" demonstrates OpenGL occlusion query in OSG using the OcclusionQueryNode.");
719    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] [filename(s)]");
720    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display command line parameters");
721
722    // if user request help write it out to cout.
723    if (arguments.read("-h") || arguments.read("--help"))
724    {
725        arguments.getApplicationUsage()->write(std::cout, osg::ApplicationUsage::COMMAND_LINE_OPTION);
726        return 1;
727    }
728
729    // report any errors if they have occurred when parsing the program arguments.
730    if (arguments.errors())
731    {
732        arguments.writeErrorMessages(std::cout);
733        return 1;
734    }
735
736    osgViewer::Viewer viewer( arguments );
737
738    // add the state manipulator
739    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
740
741    // add the stats handler
742    viewer.addEventHandler(new osgViewer::StatsHandler);
743
744    // add the help handler
745    viewer.addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage()));
746
747    bool optimize = arguments.read( "--opt" );
748
749    // load the specified model
750    osg::ref_ptr<osg::Node> root = 0;
751
752    if (arguments.argc()>1)
753    {
754        root = osgDB::readNodeFiles( arguments );
755        if (root.valid())
756        {
757            // Run a NodeVisitor to insert OcclusionQueryNodes in the scene graph.
758            OcclusionQueryVisitor oqv;
759            root->accept( oqv );
760        }
761        else
762        {
763            std::cout << arguments.getApplicationName() <<": unable to load specified data." << std::endl;
764            return 1;
765        }
766    }
767    else
768    {
769        root = createStockScene().get();
770        if (!root)
771        {
772            std::cout << arguments.getApplicationName() <<": Failed to create stock scene." << std::endl;
773            return 1;
774        }
775    }
776
777    // any option left unread are converted into errors to write out later.
778    arguments.reportRemainingOptionsAsUnrecognized();
779
780    // report any errors if they have occurred when parsing the program arguments.
781    if (arguments.errors())
782    {
783        arguments.writeErrorMessages(std::cout);
784        return 1;
785    }
786
787
788    // optimize the scene graph, remove redundant nodes and state etc.
789    if (optimize)
790    {
791        osgUtil::Optimizer optimizer;
792        optimizer.optimize( root.get() );
793    }
794
795    viewer.setSceneData( root.get() );
796
797    KeyHandler* kh = new KeyHandler( *root );
798    viewer.addEventHandler( kh );
799
800    return viewer.run();
801}
Note: See TracBrowser for help on using the browser.