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

Revision 13502, 23.0 kB (checked in by robert, 5 days ago)

Moved widgets from VolumeEditorWidget? to TransferFunctionWidget?, and widget utilities into WidgetUtils?.

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