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

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

Changed the osgUI behaviour so that events are set to be handled by Widgets that have focus even if they don't directly use them.

  • 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#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;
246        }
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{
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
265    _state = oqn->getQueryStateSet();
266    _debugState = oqn->getDebugStateSet();
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;
312
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.
352                oqn->setQueryStateSet( _state.get() );
353                oqn->setDebugStateSet( _debugState.get() );
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
396void
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.
490class KeyHandler : public osgGA::GUIEventHandler
491{
492public:
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                {
538                    if (osgDB::writeNodeFile( _node, "saved_model.osgt" ))
539                        osg::notify( osg::ALWAYS ) << "osgOQ: Wrote scene graph to \"saved_model.osgt\"" << std::endl;
540                    else
541                        osg::notify( osg::ALWAYS ) << "osgOQ: Wrote failed for \"saved_model.osgt\"" << std::endl;
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();
564    osg::PolygonMode* pm = new osg::PolygonMode(
565        osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL );
566    state->setAttributeAndModes( pm,
567        osg::StateAttribute::ON | osg::StateAttribute::PROTECTED );
568
569    osg::ref_ptr<deprecated_osg::Geometry> geom = new deprecated_osg::Geometry;
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() );
607    geom->setColorBinding( deprecated_osg::Geometry::BIND_OVERALL );
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() );
612    geom->setNormalBinding( deprecated_osg::Geometry::BIND_PER_PRIMITIVE );
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
631//  * Draw the triangles as wireframe
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();
638
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
647    osg::ref_ptr<deprecated_osg::Geometry> geom = new deprecated_osg::Geometry;
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 );
657#define RAND_NEG1_TO_1 ( ((rand()%20)-10)*.1 )
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.
671    geom->setColorBinding( deprecated_osg::Geometry::BIND_PER_PRIMITIVE );
672    c->resize( num );
673
674#define RAND_0_TO_1 ( (rand()%10)*.1 )
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    }
733
734    osgViewer::Viewer viewer( arguments );
735
736    // add the state manipulator
737    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
738
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
745    bool optimize = arguments.read( "--opt" );
746
747    // load the specified model
748    osg::ref_ptr<osg::Node> root = 0;
749
750    if (arguments.argc()>1)
751    {
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    {
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.