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

Revision 13557, 23.0 kB (checked in by robert, 43 hours ago)

Release OpenSceneGraph-3.3.3

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