Thanks Paul, changes now merged and submitted to svn/trunk.

On Tue, Dec 22, 2009 at 9:31 PM, Paul Martz <[email protected]> wrote:
> Hi Robert -- Please commit this when you have a chance, and Happy Christmas.
>
> OcclusionQueryNode was incorrectly marking itself as DYNAMIC, so I removed
> that code. And I also found some uses of dynamic_cast that could be changed
> to static_cast.
>
> Thanks,
> --
> Paul Martz
> Skew Matrix Software LLC
> _http://www.skew-matrix.com_ <http://www.skew-matrix.com/>
> +1 303 859 9466
>
>
> //
> // Copyright (C) 2007 Skew Matrix Software LLC (http://www.skew-matrix.com)
> //
> // This library is open source and may be redistributed and/or modified
> under
> // the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
> // (at your option) any later version.  The full license is in LICENSE file
> // included with this distribution, and on the openscenegraph.org website.
> //
> // This library is distributed in the hope that it will be useful,
> // but WITHOUT ANY WARRANTY; without even the implied warranty of
> // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> // OpenSceneGraph Public License for more details.
> //
>
> #include <osg/OcclusionQueryNode>
> #include <OpenThreads/ScopedLock>
> #include <osg/Timer>
> #include <osg/Notify>
> #include <osg/CopyOp>
> #include <osg/Vec3>
> #include <osg/MatrixTransform>
> #include <osg/Group>
> #include <osg/Geode>
> #include <osg/Geometry>
> #include <osg/BoundingBox>
> #include <osg/BoundingSphere>
> #include <osg/Referenced>
> #include <osg/ComputeBoundsVisitor>
> #include <osg/StateSet>
> #include <osg/StateAttribute>
> #include <osg/PolygonMode>
> #include <osg/ColorMask>
> #include <osg/PolygonOffset>
> #include <osg/Depth>
> #include <map>
> #include <vector>
>
> #include <OpenThreads/Thread>
>
>
> typedef osg::buffered_value< osg::ref_ptr< osg::Drawable::Extensions > >
> OcclusionQueryBufferedExtensions;
> static OcclusionQueryBufferedExtensions s_OQ_bufferedExtensions;
>
> //
> // Support classes, used by (and private to) OcclusionQueryNode.
> //   (Note a lot of this is historical. OcclusionQueryNode formaerly
> //   existed as a NodeKit outside the core OSG distribution. Many
> //   of these classes existed in their own separate header and
> //   source files.)
>
>
> // Create and return a StateSet appropriate for performing an occlusion
> //   query test (disable lighting, texture mapping, etc). Probably some
> //   room for improvement here. Could disable shaders, for example.
> osg::StateSet*
> initOQState()
> {
>    osg::StateSet* state = new osg::StateSet;
>    // TBD Possible bug, need to allow user to set render bin number.
>    state->setRenderBinDetails( 9, "RenderBin" );
>
>    state->setMode( GL_LIGHTING, osg::StateAttribute::OFF |
>        osg::StateAttribute::PROTECTED);
>    state->setTextureMode( 0, GL_TEXTURE_2D, osg::StateAttribute::OFF |
>        osg::StateAttribute::PROTECTED);
>    state->setMode( GL_CULL_FACE, osg::StateAttribute::ON |
>        osg::StateAttribute::PROTECTED);
>
>    osg::ColorMask* cm = new osg::ColorMask( false, false, false, false );
>    state->setAttributeAndModes( cm, osg::StateAttribute::ON |
>        osg::StateAttribute::PROTECTED);
>    osg::Depth* d = new osg::Depth( osg::Depth::LEQUAL, 0.f, 1.f, false );
>    state->setAttributeAndModes( d, osg::StateAttribute::ON |
>        osg::StateAttribute::PROTECTED);
>    osg::PolygonMode* pm = new osg::PolygonMode(
>        osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL );
>    state->setAttributeAndModes( pm, osg::StateAttribute::ON |
>        osg::StateAttribute::PROTECTED);
>
>    osg::PolygonOffset* po = new osg::PolygonOffset( -1., -1. );
>    state->setAttributeAndModes( po, osg::StateAttribute::ON |
>        osg::StateAttribute::PROTECTED);
>
>    return state;
> }
>
> // Create and return a StateSet for rendering a debug representation of
> query geometry.
> osg::StateSet*
> initOQDebugState()
> {
>    osg::StateSet* debugState = new osg::StateSet;
>
>    debugState->setMode( GL_LIGHTING, osg::StateAttribute::OFF |
>        osg::StateAttribute::PROTECTED);
>    debugState->setTextureMode( 0, GL_TEXTURE_2D, osg::StateAttribute::OFF |
>        osg::StateAttribute::PROTECTED);
>    debugState->setMode( GL_CULL_FACE, osg::StateAttribute::ON |
>        osg::StateAttribute::PROTECTED);
>
>    osg::PolygonMode* pm = new osg::PolygonMode(
>        osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE );
>    debugState->setAttributeAndModes( pm, osg::StateAttribute::ON |
>        osg::StateAttribute::PROTECTED);
>
>    osg::PolygonOffset* po = new osg::PolygonOffset( -1., -1. );
>    debugState->setAttributeAndModes( po, osg::StateAttribute::ON |
>        osg::StateAttribute::PROTECTED);
>
>    return debugState;
> }
>
>
> // TestResult -- stores (per context) results of an occlusion query
> //   test performed by QueryGeometry. An OcclusionQueryNode has a
> //   Geode owning a single QueryGeometry that
> //   draws the occlusion query geometry. QueryGeometry keeps a
> //   TestResult per context to store the result/status of each query.
> // Accessed during the cull and draw traversals.
> class TestResult : public osg::Referenced
> {
> public:
>    TestResult() : _init( false ), _id( 0 ), _contextID( 0 ), _active( false
> ), _numPixels( 0 ) {}
>    ~TestResult() {}
>
>    bool _init;
>
>    // Query ID for this context.
>    GLuint _id;
>    // Context ID owning this query ID.
>    unsigned int _contextID;
>
>    // Set to true when a query gets issued and set to
>    //   false when the result is retrieved.
>    mutable bool _active;
>
>    // Result of last query.
>    GLint _numPixels;
> };
>
> // QueryGeometry -- A Drawable that performs an occlusion query,
> //   using its geometric data as the query geometry.
> class QueryGeometry : public osg::Geometry
> {
> public:
>    QueryGeometry( const std::string& oqnName=std::string("") );
>    ~QueryGeometry();
>
>    void reset();
>
>    // TBD implement copy constructor
>
>    virtual void drawImplementation( osg::RenderInfo& renderInfo ) const;
>
>    unsigned int getNumPixels( const osg::Camera* cam );
>
>
>    void releaseGLObjects( osg::State* state = 0 );
>    static void deleteQueryObject( unsigned int contextID, GLuint handle );
>    static void flushDeletedQueryObjects( unsigned int contextID, double
> currentTime, double& availableTime );
>    static void discardDeletedQueryObjects( unsigned int contextID );
>
> protected:
>    typedef std::map< const osg::Camera*, TestResult > ResultMap;
>    mutable ResultMap _results;
>    mutable OpenThreads::Mutex _mapMutex;
>
>    // Needed for debug only
>    std::string _oqnName;
> };
>
> struct RetrieveQueriesCallback : public osg::Camera::DrawCallback
> {
>    typedef std::vector<TestResult*> ResultsVector;
>    ResultsVector _results;
>
>    RetrieveQueriesCallback( osg::Drawable::Extensions* ext=NULL )
>      : _extensionsFallback( ext )
>    {
>    }
>
>    RetrieveQueriesCallback( const RetrieveQueriesCallback&, const
> osg::CopyOp& ) {}
>    META_Object( osgOQ, RetrieveQueriesCallback )
>
>    virtual void operator() (const osg::Camera& camera) const
>    {
>        if (_results.empty())
>            return;
>
>        const osg::Timer& timer = *osg::Timer::instance();
>        osg::Timer_t start_tick = timer.tick();
>        double elapsedTime( 0. );
>        int count( 0 );
>
>        osg::Drawable::Extensions* ext;
>        if (camera.getGraphicsContext())
>        {
>            // The typical path, for osgViewer-based applications or any
>            //   app that has set up a valid GraphicsCOntext for the Camera.
>            unsigned int contextID =
> camera.getGraphicsContext()->getState()->getContextID();
>            RetrieveQueriesCallback* const_this =
> const_cast<RetrieveQueriesCallback*>( this );
>            ext = const_this->getExtensions( contextID, true );
>        }
>        else
>        {
>            // No valid GraphicsContext in the Camera. This might happen in
>            //   SceneView-based apps. Rely on the creating code to have
> passed
>            //   in a valid Extensions pointer, and hope it's valid for any
>            //   context that might be current.
>            osg::notify( osg::DEBUG_INFO ) << "osgOQ: RQCB: Using fallback
> path to obtain Extensions pointer." << std::endl;
>            ext = _extensionsFallback;
>            if (!ext)
>            {
>                osg::notify( osg::FATAL ) << "osgOQ: RQCB: Extensions pointer
> fallback is NULL." << std::endl;
>                return;
>            }
>        }
>
>        ResultsVector::const_iterator it = _results.begin();
>        while (it != _results.end())
>        {
>            TestResult* tr = const_cast<TestResult*>( *it );
>
>            if (!tr->_active || !tr->_init)
>            {
>                // This test wasn't executed last frame. This is probably
> because
>                //   a parent node failed the OQ test, this node is outside
> the
>                //   view volume, or we didn't run the test because we had
> not
>                //   exceeded visibleQueryFrameCount.
>                // Do not obtain results from OpenGL.
>                it++;
>                continue;
>            }
>
>            osg::notify( osg::DEBUG_INFO ) <<
>                "osgOQ: RQCB: Retrieving..." << std::endl;
>
> #ifdef FORCE_QUERY_RESULT_AVAILABLE_BEFORE_RETRIEVAL
>
>            // Should not need to do this, but is required on some platforms
> to
>            // work aroung issues in the device driver. For example, without
> this
>            // code, we've seen crashes on 64-bit Mac/Linux NVIDIA systems
> doing
>            // multithreaded, multipipe rendering (as in a CAVE).
>            // Tried with ATI and verified this workaround is not needed; the
>            //   problem is specific to NVIDIA.
>            GLint ready( 0 );
>            while( !ready )
>            {
>                // Apparently, must actually sleep here to avoid issues w/
> NVIDIA Quadro.
>                OpenThreads::Thread::microSleep( 5 );
>                ext->glGetQueryObjectiv( tr->_id, GL_QUERY_RESULT_AVAILABLE,
> &ready );
>            };
> #endif
>
>            ext->glGetQueryObjectiv( tr->_id, GL_QUERY_RESULT,
> &(tr->_numPixels) );
>            if (tr->_numPixels < 0)
>                osg::notify( osg::WARN ) << "osgOQ: RQCB: " <<
>                "glGetQueryObjectiv returned negative value (" <<
> tr->_numPixels << ")." << std::endl;
>
>            // Either retrieve last frame's results, or ignore it because the
>            //   camera is inside the view. In either case, _active is now
> false.
>            tr->_active = false;
>
>            it++;
>            count++;
>        }
>
>        elapsedTime = timer.delta_s(start_tick,timer.tick());
>        osg::notify( osg::INFO ) << "osgOQ: RQCB: " << "Retrieved " << count
> <<
>            " queries in " << elapsedTime << " seconds." << std::endl;
>    }
>
>    void reset()
>    {
>        _results.clear();
>    }
>
>    void add( TestResult* tr )
>    {
>        _results.push_back( tr );
>    }
>
>    osg::Drawable::Extensions* getExtensions( unsigned int contextID, bool
> createIfNotInitalized )
>    {
>        if (!s_OQ_bufferedExtensions[ contextID ] && createIfNotInitalized)
>            s_OQ_bufferedExtensions[ contextID ] = new
> osg::Drawable::Extensions( contextID );
>        return s_OQ_bufferedExtensions[ contextID ].get();
>    }
>
>
>    osg::Drawable::Extensions* _extensionsFallback;
> };
>
>
>
> // PreDraw callback; clears the list of Results from the PostDrawCallback
> (above).
> struct ClearQueriesCallback : public osg::Camera::DrawCallback
> {
>    ClearQueriesCallback() : _rqcb( NULL ) {}
>    ClearQueriesCallback( const ClearQueriesCallback&, const osg::CopyOp& )
> {}
>    META_Object( osgOQ, ClearQueriesCallback )
>
>    virtual void operator() (const osg::Camera&) const
>    {
>        if (!_rqcb)
>        {
>            osg::notify( osg::FATAL ) << "osgOQ: CQCB: Invalid RQCB." <<
> std::endl;
>            return;
>        }
>        _rqcb->reset();
>    }
>
>    RetrieveQueriesCallback* _rqcb;
> };
>
>
> // static cache of deleted query objects which can only
> // be completely deleted once the appropriate OpenGL context
> // is set.
> typedef std::list< GLuint > QueryObjectList;
> typedef osg::buffered_object< QueryObjectList > DeletedQueryObjectCache;
>
> static OpenThreads::Mutex s_mutex_deletedQueryObjectCache;
> static DeletedQueryObjectCache s_deletedQueryObjectCache;
>
> QueryGeometry::QueryGeometry( const std::string& oqnName )
>  : _oqnName( oqnName )
> {
>    // TBD check to see if we can have this on.
>    setUseDisplayList( false );
> }
>
> QueryGeometry::~QueryGeometry()
> {
>    reset();
> }
>
>
> void
> QueryGeometry::reset()
> {
>    OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _mapMutex );
>
>    ResultMap::iterator it = _results.begin();
>    while (it != _results.end())
>    {
>        TestResult& tr = it->second;
>        if (tr._init)
>            QueryGeometry::deleteQueryObject( tr._contextID, tr._id );
>        it++;
>    }
>    _results.clear();
> }
>
> // After 1.2, param 1 changed from State to RenderInfo.
> // Warning: Version was still 1.2 on dev branch long after the 1.2 release,
> //   and finally got bumped to 1.9 in April 2007.
> void
> QueryGeometry::drawImplementation( osg::RenderInfo& renderInfo ) const
> {
>    unsigned int contextID = renderInfo.getState()->getContextID();
>    osg::Drawable::Extensions* ext = getExtensions( contextID, true );
>    osg::Camera* cam = renderInfo.getCurrentCamera();
>
>    // Add callbacks if necessary.
>    if (!cam->getPostDrawCallback())
>    {
>        RetrieveQueriesCallback* rqcb = new RetrieveQueriesCallback( ext );
>        cam->setPostDrawCallback( rqcb );
>
>        ClearQueriesCallback* cqcb = new ClearQueriesCallback;
>        cqcb->_rqcb = rqcb;
>        cam->setPreDrawCallback( cqcb );
>    }
>
>    // Get TestResult from Camera map
>    TestResult* tr;
>    {
>        OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _mapMutex );
>        tr = &( _results[ cam ] );
>    }
>
>    // Add TestResult to RQCB.
>    RetrieveQueriesCallback* rqcb = dynamic_cast<
>        RetrieveQueriesCallback* >( cam->getPostDrawCallback() );
>    if (!rqcb)
>    {
>        osg::notify( osg::FATAL ) << "osgOQ: QG: Invalid RQCB." << std::endl;
>        return;
>    }
>    rqcb->add( tr );
>
>
>    // Issue query
>    if (!tr->_init)
>    {
>        ext->glGenQueries( 1, &(tr->_id) );
>        tr->_contextID = contextID;
>        tr->_init = true;
>    }
>
>    osg::notify( osg::DEBUG_INFO ) <<
>        "osgOQ: QG: Querying for: " << _oqnName << std::endl;
>
>    ext->glBeginQuery( GL_SAMPLES_PASSED_ARB, tr->_id );
>    osg::Geometry::drawImplementation( renderInfo );
>    ext->glEndQuery( GL_SAMPLES_PASSED_ARB );
>    tr->_active = true;
>
>
>    osg::notify( osg::DEBUG_INFO ) <<
>        "osgOQ: QG. OQNName: " << _oqnName <<
>        ", Ctx: " << contextID <<
>        ", ID: " << tr->_id << std::endl;
> #ifdef _DEBUG
>    {
>        GLenum err;
>        if ((err = glGetError()) != GL_NO_ERROR)
>            osg::notify( osg::FATAL ) <<
>            "osgOQ: QG: OpenGL error: " << err << "." << std::endl;
>    }
> #endif
>
>
> }
>
>
> unsigned int
> QueryGeometry::getNumPixels( const osg::Camera* cam )
> {
>    TestResult tr;
>    {
>        OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _mapMutex );
>        tr =  _results[ cam ];
>    }
>    return tr._numPixels;
> }
>
>
> void
> QueryGeometry::releaseGLObjects( osg::State* state )
> {
>    if (!state)
>        // delete all query IDs for all contexts.
>        reset();
>
>    else
>    {
>        // Delete all query IDs for the specified context.
>        unsigned int contextID = state->getContextID();
>        ResultMap::iterator it = _results.begin();
>        while (it != _results.end())
>        {
>            TestResult& tr = it->second;
>            if (tr._contextID == contextID)
>            {
>                QueryGeometry::deleteQueryObject( contextID, tr._id );
>                tr._init = false;
>            }
>            it++;
>        }
>    }
> }
>
> void
> QueryGeometry::deleteQueryObject( unsigned int contextID, GLuint handle )
> {
>    if (handle!=0)
>    {
>        OpenThreads::ScopedLock< OpenThreads::Mutex > lock(
> s_mutex_deletedQueryObjectCache );
>
>        // insert the handle into the cache for the appropriate context.
>        s_deletedQueryObjectCache[contextID].push_back( handle );
>    }
> }
>
>
> void
> QueryGeometry::flushDeletedQueryObjects( unsigned int contextID, double
> /*currentTime*/, double& availableTime )
> {
>    // if no time available don't try to flush objects.
>    if (availableTime<=0.0) return;
>
>    const osg::Timer& timer = *osg::Timer::instance();
>    osg::Timer_t start_tick = timer.tick();
>    double elapsedTime = 0.0;
>
>    {
>        OpenThreads::ScopedLock<OpenThreads::Mutex>
> lock(s_mutex_deletedQueryObjectCache);
>
>        const osg::Drawable::Extensions* extensions = getExtensions(
> contextID, true );
>
>        QueryObjectList& qol = s_deletedQueryObjectCache[contextID];
>
>        for(QueryObjectList::iterator titr=qol.begin();
>            titr!=qol.end() && elapsedTime<availableTime;
>            )
>        {
>            extensions->glDeleteQueries( 1L, &(*titr ) );
>            titr = qol.erase(titr);
>            elapsedTime = timer.delta_s(start_tick,timer.tick());
>        }
>    }
>
>    availableTime -= elapsedTime;
> }
>
> void
> QueryGeometry::discardDeletedQueryObjects( unsigned int contextID )
> {
>    OpenThreads::ScopedLock< OpenThreads::Mutex > lock(
> s_mutex_deletedQueryObjectCache );
>    QueryObjectList& qol = s_deletedQueryObjectCache[ contextID ];
>    qol.clear();
> }
>
> // End support classes
> //
>
>
>
> namespace osg
> {
>
>
> OcclusionQueryNode::OcclusionQueryNode()
>  : _enabled( true ),
>    _visThreshold( 500 ),
>    _queryFrameCount( 5 ),
>    _debugBB( false )
> {
>    // OQN has two Geode member variables, one for doing the
>    //   query and one for rendering the debug geometry.
>    //   Create and initialize them.
>    createSupportNodes();
> }
>
> OcclusionQueryNode::~OcclusionQueryNode()
> {
> }
>
> OcclusionQueryNode::OcclusionQueryNode( const OcclusionQueryNode& oqn, const
> osg::CopyOp& copyop )
>  : Group( oqn, copyop ),
>    _passed( false )
> {
>    _enabled = oqn._enabled;
>    _visThreshold = oqn._visThreshold;
>    _queryFrameCount = oqn._queryFrameCount;
>    _debugBB = oqn._debugBB;
>
>    // Regardless of shallow or deep, create unique support nodes.
>    createSupportNodes();
> }
>
>
> bool
> OcclusionQueryNode::getPassed( const osg::Camera* camera, float
> distanceToEyePoint )
> {
>    if ( !_enabled )
>        // Queries are not enabled. The caller should be
> osgUtil::CullVisitor,
>        //   return true to traverse the subgraphs.
>        return true;
>
>    if (_queryGeode->getDrawable( 0 ) == NULL)
>    {
>        osg::notify( osg::FATAL ) <<
>            "osgOQ: OcclusionQueryNode: No QueryGeometry." << std::endl;
>        // Something's broke. Return true so we at least render correctly.
>        return true;
>    }
>    QueryGeometry* qg = static_cast< QueryGeometry* >(
> _queryGeode->getDrawable( 0 ) );
>
>    // If the distance to the bounding sphere shell is positive, retrieve
>    //   the results. Others (we're inside the BS shell) we are considered
>    //   to have passed and don't need to retrieve the query.
>    const osg::BoundingSphere& bs = getBound();
>    float distance = distanceToEyePoint  - bs._radius;
>    _passed = ( distance <= 0.f );
>    if (!_passed)
>    {
>        int result = qg->getNumPixels( camera );
>        _passed = ( (unsigned int)(result) > _visThreshold );
>    }
>
>    return _passed;
> }
>
> void
> OcclusionQueryNode::traverseQuery( const osg::Camera* camera,
> osg::NodeVisitor& nv )
> {
>    bool issueQuery;
>    {
>        const int curFrame = nv.getTraversalNumber();
>
>        OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _frameCountMutex );
>        int& lastQueryFrame = _frameCountMap[ camera ];
>        issueQuery = (curFrame - lastQueryFrame >= _queryFrameCount);
>        if (issueQuery)
>            lastQueryFrame = curFrame;
>    }
>    if (issueQuery)
>        _queryGeode->accept( nv );
> }
>
> void
> OcclusionQueryNode::traverseDebug( osg::NodeVisitor& nv )
> {
>    if (_debugBB)
>        // If requested, display the debug geometry
>        _debugGeode->accept( nv );
> }
>
> osg::BoundingSphere
> OcclusionQueryNode::computeBound() const
> {
>    {
>        // Need to make this routine thread-safe. Typically called by the
> update
>        //   Visitor, or just after the update traversal, but could be called
> by
>        //   an application thread or by a non-osgViewer application.
>        OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _computeBoundMutex
> )  ;
>
>        // This is the logical place to put this code, but the method is
> const. Cast
>        //   away constness to compute the bounding box and modify the query
> geometry.
>        osg::OcclusionQueryNode* nonConstThis =
> const_cast<osg::OcclusionQueryNode*>( this );
>
>
>        osg::ComputeBoundsVisitor cbv;
>        nonConstThis->accept( cbv );
>        osg::BoundingBox bb = cbv.getBoundingBox();
>
>        osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;
>        v->resize( 8 );
>        (*v)[0] = osg::Vec3( bb._min.x(), bb._min.y(), bb._min.z() );
>        (*v)[1] = osg::Vec3( bb._max.x(), bb._min.y(), bb._min.z() );
>        (*v)[2] = osg::Vec3( bb._max.x(), bb._min.y(), bb._max.z() );
>        (*v)[3] = osg::Vec3( bb._min.x(), bb._min.y(), bb._max.z() );
>        (*v)[4] = osg::Vec3( bb._max.x(), bb._max.y(), bb._min.z() );
>        (*v)[5] = osg::Vec3( bb._min.x(), bb._max.y(), bb._min.z() );
>        (*v)[6] = osg::Vec3( bb._min.x(), bb._max.y(), bb._max.z() );
>        (*v)[7] = osg::Vec3( bb._max.x(), bb._max.y(), bb._max.z() );
>
>        osg::Geometry* geom = static_cast< osg::Geometry* >(
> nonConstThis->_queryGeode->getDrawable( 0 ) );
>        geom->setVertexArray( v.get() );
>
>        geom = static_cast< osg::Geometry* >(
> nonConstThis->_debugGeode->getDrawable( 0 ) );
>        geom->setVertexArray( v.get() );
>    }
>
>    return Group::computeBound();
> }
>
>
> // Should only be called outside of cull/draw. No thread issues.
> void
> OcclusionQueryNode::setQueriesEnabled( bool enable )
> {
>    _enabled = enable;
> }
>
> // Should only be called outside of cull/draw. No thread issues.
> void
> OcclusionQueryNode::setDebugDisplay( bool debug )
> {
>    _debugBB = debug;
> }
> bool
> OcclusionQueryNode::getDebugDisplay() const
> {
>    return _debugBB;
> }
>
>
>
> void
> OcclusionQueryNode::setQueryStateSet( osg::StateSet* ss )
> {
>    if (!_queryGeode)
>    {
>        osg::notify( osg::WARN ) << "osgOQ: OcclusionQueryNode:: Invalid
> query support node." << std::endl;
>        return;
>    }
>
>    _queryGeode->setStateSet( ss );
> }
> osg::StateSet*
> OcclusionQueryNode::getQueryStateSet()
> {
>    if (!_queryGeode)
>    {
>        osg::notify( osg::WARN ) << "osgOQ: OcclusionQueryNode:: Invalid
> query support node." << std::endl;
>        return NULL;
>    }
>    return _queryGeode->getStateSet();
> }
>
> const osg::StateSet*
> OcclusionQueryNode::getQueryStateSet() const
> {
>    if (!_queryGeode)
>    {
>        osg::notify( osg::WARN ) << "osgOQ: OcclusionQueryNode:: Invalid
> query support node." << std::endl;
>        return NULL;
>    }
>    return _queryGeode->getStateSet();
> }
>
> void
> OcclusionQueryNode::setDebugStateSet( osg::StateSet* ss )
> {
>    if (!_debugGeode)
>    {
>        osg::notify( osg::WARN ) << "osgOQ: OcclusionQueryNode:: Invalid
> debug support node." << std::endl;
>        return;
>    }
>    _debugGeode->setStateSet( ss );
> }
>
> osg::StateSet*
> OcclusionQueryNode::getDebugStateSet()
> {
>    if (!_debugGeode.valid())
>    {
>        osg::notify( osg::WARN ) << "osgOQ: OcclusionQueryNode:: Invalid
> debug support node." << std::endl;
>        return NULL;
>    }
>    return _debugGeode->getStateSet();
> }
> const osg::StateSet*
> OcclusionQueryNode::getDebugStateSet() const
> {
>    if (!_debugGeode.valid())
>    {
>        osg::notify( osg::WARN ) << "osgOQ: OcclusionQueryNode:: Invalid
> debug support node." << std::endl;
>        return NULL;
>    }
>    return _debugGeode->getStateSet();
> }
>
> bool
> OcclusionQueryNode::getPassed() const
> {
>    return _passed;
> }
>
>
> void
> OcclusionQueryNode::createSupportNodes()
> {
>    GLushort indices[] = { 0, 1, 2, 3,  4, 5, 6, 7,
>        0, 3, 6, 5,  2, 1, 4, 7,
>        5, 4, 1, 0,  2, 7, 6, 3 };
>
>    {
>        // Add the test geometry Geode
>        _queryGeode = new osg::Geode;
>        _queryGeode->setName( "OQTest" );
>        _queryGeode->setDataVariance( osg::Object::DYNAMIC );
>
>        osg::ref_ptr< QueryGeometry > geom = new QueryGeometry( getName() );
>        geom->setDataVariance( osg::Object::DYNAMIC );
>        geom->addPrimitiveSet( new osg::DrawElementsUShort(
>                    osg::PrimitiveSet::QUADS, 24, indices ) );
>
>        _queryGeode->addDrawable( geom.get() );
>    }
>
>    {
>        // Add a Geode that is a visual representation of the
>        //   test geometry for debugging purposes
>        _debugGeode = new osg::Geode;
>        _debugGeode->setName( "Debug" );
>        _debugGeode->setDataVariance( osg::Object::DYNAMIC );
>
>        osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
>        geom->setDataVariance( osg::Object::DYNAMIC );
>
>        osg::ref_ptr<osg::Vec4Array> ca = new osg::Vec4Array;
>        ca->push_back( osg::Vec4( 1.f, 1.f, 1.f, 1.f ) );
>        geom->setColorArray( ca.get() );
>        geom->setColorBinding( osg::Geometry::BIND_OVERALL );
>
>        geom->addPrimitiveSet( new osg::DrawElementsUShort(
>                    osg::PrimitiveSet::QUADS, 24, indices ) );
>
>        _debugGeode->addDrawable( geom.get() );
>    }
>
>    // Creste state sets. Note that the osgOQ visitors (which place OQNs
> throughout
>    //   the scene graph) create a single instance of these StateSets shared
>    //   between all OQNs for efficiency.
>    setQueryStateSet( initOQState() );
>    setDebugStateSet( initOQDebugState() );
> }
>
>
> void
> OcclusionQueryNode::releaseGLObjects( osg::State* state ) const
> {
>    if(_queryGeode->getDrawable( 0 ) != NULL)
>    {
>        // Query object discard and deletion is handled by QueryGeometry
> support class.
>        OcclusionQueryNode* nonConstThis = const_cast< OcclusionQueryNode* >(
> this );
>        QueryGeometry* qg = static_cast< QueryGeometry* >(
> nonConstThis->_queryGeode->getDrawable( 0 ) );
>        qg->releaseGLObjects( state );
>    }
> }
>
> void
> OcclusionQueryNode::flushDeletedQueryObjects( unsigned int contextID, double
> currentTime, double& availableTime )
> {
>    // Query object discard and deletion is handled by QueryGeometry support
> class.
>    QueryGeometry::flushDeletedQueryObjects( contextID, currentTime,
> availableTime );
> }
>
> void
> OcclusionQueryNode::discardDeletedQueryObjects( unsigned int contextID )
> {
>    // Query object discard and deletion is handled by QueryGeometry support
> class.
>    QueryGeometry::discardDeletedQueryObjects( contextID );
> }
>
>
> }
>
> _______________________________________________
> osg-submissions mailing list
> [email protected]
> http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
>
>
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to