virtual void operator () (osg::RenderInfo& renderInfo) const
        {
            osg::BufferBindingReadBack::operator () (renderInfo) ;
            //_acbb->readData(*renderInfo.getState(), *_atomicCounterArray);
             osg::UIntArray * _atomicCounterArray=dynamic_cast<osg::UIntArray *>(_bb->getBufferData());

            unsigned int numPixel = osg::maximum(1u, _atomicCounterArray->front());

            if ((renderInfo.getView()->getFrameStamp()->getFrameNumber() % 10) == 0)
            {
                OSG_WARN << "osgatomiccounter : draw " << numPixel << " pixels." << std::endl;
            }

            _invNumPixelUniform->set( 1.0f / static_cast<float>(numPixel) );
        }
Example #2
0
void TritonNode::OceanDrawable::drawImplementation( osg::RenderInfo& renderInfo ) const
{
    osg::State* state = renderInfo.getState();
    state->disableAllVertexArrays();
    
    _triton->initializeTriton( renderInfo );
#ifdef USE_SILVERLINING_SKY
    if ( _triton->atmosphere() && _triton->environment() )
    {
        void* ptr = NULL;
        if ( _triton->atmosphere()->GetEnvironmentMap(ptr) )
            _triton->environment()->SetEnvironmentMap( (Triton::TextureHandle)ptr );
    }
#endif
    
    if ( _triton->ocean() )
    {
        double time = renderInfo.getView()->getFrameStamp()->getSimulationTime();
        Triton::Ocean* ocean = _triton->ocean();
        if ( _oceanMeshes.size()>0 )
        {
            for ( unsigned int i=0; i<_oceanMeshes.size(); ++i )
            {
                // Bind VBO before SetPatchShader()
                state->setVertexPointer( _oceanMeshes[i].vertices.get() );
                
                // Render mesh in an ocean favor
                ocean->SetPatchShader( time, 3 * sizeof(float), 0, false, NULL );
                _oceanMeshes[i].primitiveSet->draw( *state, true );
                ocean->UnsetPatchShader();
            }
            state->unbindVertexBufferObject();
            state->unbindElementBufferObject();
        }
        else
            ocean->Draw( time );
    }
    state->dirtyAllVertexArrays();
}
Example #3
0
void NoesisDrawable::drawImplementation( osg::RenderInfo& renderInfo ) const
{
    unsigned int contextID = renderInfo.getContextID();
    if ( !_initialized )
    {
        if ( !NoesisSystemManager::contextInitialized )
        {
            NsGetKernel()->InitSystems();
            NoesisSystemManager::contextInitialized = true;
        }

        NoesisDrawable* constMe = const_cast<NoesisDrawable*>( this );
        constMe->initializeUI( renderInfo );
        constMe->registerEventHandlers();
        _activeContextID = contextID;
        _initialized = true;
    }
    else if ( contextID==_activeContextID )
    {
        if ( _dirty )
        {
            _uiRenderer->SetSize( _width, _height );
            _dirty = false;
        }
        
        osg::State* state = renderInfo.getState();
        state->disableAllVertexArrays();
        
        // Make sure the client unit and active unit are unified
        state->setClientActiveTextureUnit( 0 );
        state->setActiveTextureUnit( 0 );
        
#if !PARALLEL_UPDATING_AND_RENDERING
        // Update
        NsGetKernel()->Tick();

        osg::FrameStamp* fs = renderInfo.getView()->getFrameStamp();
        if ( fs ) _uiRenderer->Update( fs->getSimulationTime() );
#endif
        // Obtain commands
        RenderCommands renderCommands = _uiRenderer->WaitForUpdate();
        osg::FBOExtensions* fbo = osg::FBOExtensions::instance(contextID, true);

        // Render offscreen
        if ( fbo )
        {;
            _uiRenderer->Render( renderCommands.offscreenCommands.GetPtr() );
            fbo->glBindFramebuffer( GL_FRAMEBUFFER_EXT, 0 );
        }

        // Render
        _uiRenderer->Render( renderCommands.commands.GetPtr() );

        // Restore buffer states
        osg::GLBufferObject::Extensions* buf = osg::GLBufferObject::getExtensions(contextID, true);
        buf->glBindBuffer( GL_ARRAY_BUFFER_ARB, 0 );
        buf->glBindBuffer( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );

        osg::GL2Extensions* gl2 = osg::GL2Extensions::Get(contextID, true);
        gl2->glDisableVertexAttribArray( 0 );
        gl2->glDisableVertexAttribArray( 1 );
        gl2->glDisableVertexAttribArray( 2 );
        gl2->glDisableVertexAttribArray( 3 );
        gl2->glDisableVertexAttribArray( 4 );
        gl2->glDisableVertexAttribArray( 5 );
        gl2->glDisableVertexAttribArray( 6 );
    }
    else
        std::cout << "Multiple contexts are not supported at present!" << std::endl;
}
Example #4
0
void
TritonDrawable::drawImplementation(osg::RenderInfo& renderInfo) const
{
    osg::State* state = renderInfo.getState();

    state->disableAllVertexArrays();

    _TRITON->initialize( renderInfo );
    if ( !_TRITON->ready() )
        return;

    // Configure the height map generator.
    // If configuration fails, attempt to continue without a heightmap.
    if (_heightMapGenerator.valid())
    {
        bool configOK = _heightMapGenerator->configure(_TRITON->getHeightMapSize(), *state);
        if (configOK == false)
        {
            _heightMapGenerator = 0L;
            OE_WARN << LC << "Failed to establish a legal FBO configuration; disabling height map generator!" << std::endl;
        }
    }

    ::Triton::Environment* environment = _TRITON->getEnvironment();

    // Find or create the Triton camera for this OSG camera:
    CameraLocal& local = _local.get(renderInfo.getCurrentCamera());
    if (local._tritonCam == 0L)
    {
        local._tritonCam = environment->CreateCamera();
        local._tritonCam->SetName(renderInfo.getCurrentCamera()->getName().c_str());
    }
    ::Triton::Camera* tritonCam = local._tritonCam;

    osgEarth::NativeProgramAdapterCollection& adapters = _adapters[ state->getContextID() ];
    if ( adapters.empty() )
    {
        OE_INFO << LC << "Initializing Triton program adapters" << std::endl;
        const char* prefix = "oe_"; // because, don't forget osg_*
        adapters.push_back( new osgEarth::NativeProgramAdapter(state, getOceanShader(_TRITON->getOcean(), ::Triton::WATER_SURFACE, 0L, tritonCam), prefix, "WATER_SURFACE"));
        adapters.push_back( new osgEarth::NativeProgramAdapter(state, getOceanShader(_TRITON->getOcean(), ::Triton::WATER_SURFACE_PATCH, 0L, tritonCam), prefix, "WATER_SURFACE_PATCH"));
        adapters.push_back( new osgEarth::NativeProgramAdapter(state, getOceanShader(_TRITON->getOcean(), ::Triton::GOD_RAYS, 0L, tritonCam), prefix, "GOD_RAYS"));
        adapters.push_back( new osgEarth::NativeProgramAdapter(state, getOceanShader(_TRITON->getOcean(), ::Triton::SPRAY_PARTICLES, 0L, tritonCam), prefix, "SPRAY_PARTICLES"));
        adapters.push_back( new osgEarth::NativeProgramAdapter(state, getOceanShader(_TRITON->getOcean(), ::Triton::WAKE_SPRAY_PARTICLES, 0L, tritonCam), prefix, "WAKE_SPRAY_PARTICLES"));
#if 0
        // In older Triton (3.91), this line causes problems in Core profile and prevents the ocean from drawing.  In newer Triton (4.01),
        // this line causes a crash because there is no context passed in to GetShaderObject(), resulting in multiple NULL references.
        adapters.push_back( new osgEarth::NativeProgramAdapter(state, getOceanShader(_TRITON->getOcean(), ::Triton::WATER_DECALS, 0L, tritonCam), prefix, "WATER_DECALS"));
#endif
    }
    adapters.apply( state );


    // Pass the final view and projection matrices into Triton.
    if ( environment )
    {
        tritonCam->SetCameraMatrix(state->getModelViewMatrix().ptr());
        tritonCam->SetProjectionMatrix(state->getProjectionMatrix().ptr());
    }

    if (_heightMapGenerator.valid())
    {
        GLint texName;
        osg::Matrix hMM;
        if (_heightMapGenerator->getTextureAndMatrix(renderInfo, texName, hMM))
        {
            // copy the OSG matrix to a Triton matrix:
            ::Triton::Matrix4 texMat(
                hMM(0, 0), hMM(0, 1), hMM(0, 2), hMM(0, 3),
                hMM(1, 0), hMM(1, 1), hMM(1, 2), hMM(1, 3),
                hMM(2, 0), hMM(2, 1), hMM(2, 2), hMM(2, 3),
                hMM(3, 0), hMM(3, 1), hMM(3, 2), hMM(3, 3));

            environment->SetHeightMap((::Triton::TextureHandle)texName, texMat, 0L, tritonCam);
                
            OE_DEBUG << LC << "Updating height map, FN=" << renderInfo.getState()->getFrameStamp()->getFrameNumber() << std::endl;
        }
    }

    state->dirtyAllVertexArrays();

    // Now light and draw the ocean:
    if ( environment )
    {
        // User pre-draw callback:
        if (_TRITON->getCallback())
        {
            _TRITON->getCallback()->onDrawOcean(
                _TRITON->getEnvironmentWrapper(),
                _TRITON->getOceanWrapper());
        }

        // The sun position is roughly where it is in our skybox texture:

        // Since this is a simple example we will just assume that Sun is the light from View light source
        // TODO: fix this...
        osg::Light* light = renderInfo.getView() ? renderInfo.getView()->getLight() : NULL;

        // This is the light attached to View so there are no transformations above..
        // But in general case you would need to accumulate all transforms above the light into this matrix
        osg::Matrix lightLocalToWorldMatrix = osg::Matrix::identity();

        // If you don't know where the sun lightsource is attached and don't know its local to world matrix you may use
        // following elaborate scheme to grab the light source while drawing Triton ocean:
        // - Install cull callback to catch CullVisitor and record pointer to its associated RenderStage
        //   I was hoping RenderStage can be found from renderInfo in drawImplementation but I didn't figure how ...
        // - When TritonDrawable::drawImplementation is called all lights will be already applied to OpenGL
        //   then just find proper infinite directional light by scanning renderStage->PositionalStateContainer.
        // - Note that we canot scan for the lights inside cull because they may not be traversed before Triton drawable
        // - When you found interesting ligt source that can work as Sun, read its modelview matrix and lighting params
        //   Multiply light position by ( modelview * inverse camera view ) and pass this to Triton with lighting colors

        if ( light && light->getPosition().w() == 0 )
        {
            osg::Vec4 ambient = light->getAmbient();
            osg::Vec4 diffuse = light->getDiffuse();
            osg::Vec4 position = light->getPosition();

            // Compute light position/direction in the world
            position = position * lightLocalToWorldMatrix;

            // Diffuse direction and color
            environment->SetDirectionalLight(
                ::Triton::Vector3( position[0], position[1], position[2] ),
                ::Triton::Vector3( diffuse[0],  diffuse[1],  diffuse[2] ) );

            // Sun-based ambient value:
            osg::Vec3d up = osg::Vec3d(0,0,0) * renderInfo.getCurrentCamera()->getInverseViewMatrix();
            up.normalize();
            osg::Vec3d pos3 = osg::Vec3d(position.x(), position.y(), position.z());
            pos3.normalize();
            float dot = osg::clampAbove(up*pos3, 0.0); dot*=dot;
            float sunAmbient = (float)osg::clampBetween( dot, 0.0f, 0.88f );
            float fa = osg::maximum(sunAmbient, ambient[0]);

            // Ambient color based on the zenith color in the cube map
            environment->SetAmbientLight( ::Triton::Vector3(fa, fa, fa) );
        }

        else
        {
            environment->SetDirectionalLight( ::Triton::Vector3(0,0,1), ::Triton::Vector3(1,1,1) );
            environment->SetAmbientLight( ::Triton::Vector3(0.88f, 0.88f, 0.88f) );
        }

        if ( _cubeMap.valid() )
        {
            // Build transform from our cube map orientation space to native Triton orientation
            // See worldToCubeMap function used in SkyBox to orient sky texture so that sky is up and earth is down
            osg::Matrix m = osg::Matrix::rotate( osg::PI_2, osg::X_AXIS ); // = worldToCubeMap

            ::Triton::Matrix3 transformFromYUpToZUpCubeMapCoords(
                m(0,0), m(0,1), m(0,2),
                m(1,0), m(1,1), m(1,2),
                m(2,0), m(2,1), m(2,2) );

            // Grab the cube map from our sky box and give it to Triton to use as an _environment map
            // GLenum texture = renderInfo.getState()->getLastAppliedTextureAttribute( _stage, osg::StateAttribute::TEXTURE );
            environment->SetEnvironmentMap(
                (::Triton::TextureHandle)_cubeMap->getTextureObject( state->getContextID() )->id(),
                transformFromYUpToZUpCubeMapCoords );

            if( _planarReflectionMap.valid() && _planarReflectionProjection.valid() )
            {
                osg::Matrix & p = *_planarReflectionProjection;

                ::Triton::Matrix3 planarProjection(
                    p(0,0), p(0,1), p(0,2),
                    p(1,0), p(1,1), p(1,2),
                    p(2,0), p(2,1), p(2,2) );

                environment->SetPlanarReflectionMap(
                    (::Triton::TextureHandle)_planarReflectionMap->getTextureObject( state->getContextID() )->id(),
                    planarProjection,
                    0.125 );
            }
        }

        // Draw the ocean for the current time sample
        if ( _TRITON->getOcean() )
        {
            osg::GLExtensions* ext = osg::GLExtensions::Get(state->getContextID(), true);

            bool writeDepth = true;
            const osg::Depth* depth = static_cast<const osg::Depth*>(state->getLastAppliedAttribute(osg::StateAttribute::DEPTH));
            if (depth)
                writeDepth = depth->getWriteMask();

            double simTime = renderInfo.getView()->getFrameStamp()->getSimulationTime();
            simTime = fmod(simTime, 86400.0);

            _TRITON->getOcean()->Draw(
                simTime,
                writeDepth, // depth writes
                true, // draw water
                true, // draw particles
                NULL, // optional context
                tritonCam);

        }
    }
            
    // Put GL back in a state that won't confuse the OSG state tracking:
    state->dirtyAllVertexArrays();
    state->dirtyAllAttributes();
    state->dirtyAllModes();    

#ifndef OSG_GL_FIXED_FUNCTION_AVAILABLE
    // Keep OSG from reapplying GL_LIGHTING on next state change after dirtyAllModes().
    state->setModeValidity(GL_LIGHTING, false);
#endif

    // Keep an eye on this.
    // I had to remove something similar in another module (Rex engine) because it was causing
    // positional attributes (like clip planes) to re-apply with an incorrect MVM. -gw
    state->apply();    
}
void FadeText::drawImplementation(osg::RenderInfo& renderInfo) const
{

    osg::State& state = *renderInfo.getState();

    ViewBlendColourMap::iterator itr = _viewBlendColourMap.find(renderInfo.getView());
    if (itr != _viewBlendColourMap.end())
    {
        Text::drawImplementation(*renderInfo.getState(), itr->second );
    }
    else
    {
        Text::drawImplementation(*renderInfo.getState(), osg::Vec4(1.0f,1.0f,1.0f,1.0f) );
    }


    // now pass on new details

    FadeTextUserData* userData = dynamic_cast<FadeTextUserData*>(renderInfo.getUserData());
    if (!userData)
    {
        if (renderInfo.getUserData())
        {
            OSG_NOTICE<<"Warning user data not of supported type."<<std::endl;
            return;
        }

        userData = getGlobalFadeText()->createNewFadeTextUserData(renderInfo.getView());

        if (!userData)
        {
            OSG_NOTICE<<"Memory error, unable to create FadeTextUserData."<<std::endl;
            return;
        }

        renderInfo.setUserData(userData);
    }

    unsigned int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber();
    if (frameNumber != userData->_frameNumber)
    {
        // new frame so must reset UserData structure.
        userData->_frameNumber = frameNumber;
        userData->_fadeTextInView.clear();
    }

    osg::Matrix lmv = state.getModelViewMatrix();
    computeMatrix(lmv, &state);
    lmv.postMult(state.getModelViewMatrix());

    if (renderInfo.getView() && renderInfo.getView()->getCamera())
    {
        // move from camera into the view space.
        lmv.postMult(state.getInitialInverseViewMatrix());
        lmv.postMult(renderInfo.getView()->getCamera()->getViewMatrix());
    }

    FadeTextData ftd(const_cast<osgText::FadeText*>(this));

    ftd._vertices[0].set(osg::Vec3d(_textBB.xMin(),_textBB.yMin(),_textBB.zMin())*lmv);
    ftd._vertices[1].set(osg::Vec3d(_textBB.xMax(),_textBB.yMin(),_textBB.zMin())*lmv);
    ftd._vertices[2].set(osg::Vec3d(_textBB.xMax(),_textBB.yMax(),_textBB.zMin())*lmv);
    ftd._vertices[3].set(osg::Vec3d(_textBB.xMin(),_textBB.yMax(),_textBB.zMin())*lmv);

    userData->_fadeTextInView.push_back(ftd);

}
Example #6
0
void
TritonDrawable::drawImplementation(osg::RenderInfo& renderInfo) const
{
    osg::State* state = renderInfo.getState();

    state->disableAllVertexArrays();

    _TRITON->initialize( renderInfo );
    if ( !_TRITON->ready() )
        return;

    if ( _TRITON->passHeightMapToTriton() && !_terrainChangedCallback.valid() )
    {
        const_cast<TritonDrawable*>(this)->setupHeightMap(*state);
    }

    ::Triton::Environment* environment = _TRITON->getEnvironment();

    osgEarth::NativeProgramAdapterCollection& adapters = _adapters[ state->getContextID() ];
    if ( adapters.empty() )
    {
        const char* prefix = "oe_";
        adapters.push_back( new osgEarth::NativeProgramAdapter(state, (GLint)_TRITON->getOcean()->GetShaderObject(::Triton::GOD_RAYS), prefix));
        adapters.push_back( new osgEarth::NativeProgramAdapter(state, (GLint)_TRITON->getOcean()->GetShaderObject(::Triton::SPRAY_PARTICLES), prefix));
        adapters.push_back( new osgEarth::NativeProgramAdapter(state, (GLint)_TRITON->getOcean()->GetShaderObject(::Triton::WAKE_SPRAY_PARTICLES), prefix));
        adapters.push_back( new osgEarth::NativeProgramAdapter(state, (GLint)_TRITON->getOcean()->GetShaderObject(::Triton::WATER_DECALS), prefix));
        adapters.push_back( new osgEarth::NativeProgramAdapter(state, (GLint)_TRITON->getOcean()->GetShaderObject(::Triton::WATER_SURFACE_PATCH), prefix));
        adapters.push_back( new osgEarth::NativeProgramAdapter(state, (GLint)_TRITON->getOcean()->GetShaderObject(::Triton::WATER_SURFACE), prefix));
    }
    adapters.apply( state );

    // Pass the final view and projection matrices into Triton.
    if ( environment )
    {
        environment->SetCameraMatrix( state->getModelViewMatrix().ptr() );
        environment->SetProjectionMatrix( state->getProjectionMatrix().ptr() );
    }

    if ( _TRITON->passHeightMapToTriton() )
    {
        unsigned cid = renderInfo.getContextID();

        bool dirty =
            ( _contextDirty[cid] ) ||
            ( renderInfo.getView()->getCamera()->getViewMatrix()       != _viewMatrix ) ||
            ( renderInfo.getView()->getCamera()->getProjectionMatrix() != _projMatrix );

        if ( dirty )
        {
            updateHeightMap( renderInfo );
            _contextDirty[renderInfo.getContextID()] = 0;
            _viewMatrix = renderInfo.getView()->getCamera()->getViewMatrix();
            _projMatrix = renderInfo.getView()->getCamera()->getProjectionMatrix();
        }
    }

    state->dirtyAllVertexArrays();

    // Now light and draw the ocean:
    if ( environment )
    {
        // User pre-draw callback:
        if (_TRITON->getCallback())
        {
            _TRITON->getCallback()->onDrawOcean(
                _TRITON->getEnvironmentWrapper(),
                _TRITON->getOceanWrapper());
        }

        // The sun position is roughly where it is in our skybox texture:

        // Since this is a simple example we will just assume that Sun is the light from View light source
        // TODO: fix this...
        osg::Light* light = renderInfo.getView() ? renderInfo.getView()->getLight() : NULL;

        // This is the light attached to View so there are no transformations above..
        // But in general case you would need to accumulate all transforms above the light into this matrix
        osg::Matrix lightLocalToWorldMatrix = osg::Matrix::identity();

        // If you don't know where the sun lightsource is attached and don't know its local to world matrix you may use
        // following elaborate scheme to grab the light source while drawing Triton ocean:
        // - Install cull callback to catch CullVisitor and record pointer to its associated RenderStage
        //   I was hoping RenderStage can be found from renderInfo in drawImplementation but I didn't figure how ...
        // - When TritonDrawable::drawImplementation is called all lights will be already applied to OpenGL
        //   then just find proper infinite directional light by scanning renderStage->PositionalStateContainer.
        // - Note that we canot scan for the lights inside cull because they may not be traversed before Triton drawable
        // - When you found interesting ligt source that can work as Sun, read its modelview matrix and lighting params
        //   Multiply light position by ( modelview * inverse camera view ) and pass this to Triton with lighting colors

        if ( light && light->getPosition().w() == 0 )
        {
            osg::Vec4 ambient = light->getAmbient();
            osg::Vec4 diffuse = light->getDiffuse();
            osg::Vec4 position = light->getPosition();

            // Compute light position/direction in the world
            position = position * lightLocalToWorldMatrix;

            // Diffuse direction and color
            environment->SetDirectionalLight(
                ::Triton::Vector3( position[0], position[1], position[2] ),
                ::Triton::Vector3( diffuse[0],  diffuse[1],  diffuse[2] ) );

            // Sun-based ambient value:
            osg::Vec3d up = osg::Vec3d(0,0,0) * renderInfo.getCurrentCamera()->getInverseViewMatrix();
            up.normalize();
            osg::Vec3d pos3 = osg::Vec3d(position.x(), position.y(), position.z());
            pos3.normalize();
            float dot = osg::clampAbove(up*pos3, 0.0);
            dot*=dot;
            float sunAmbient = (float)osg::clampBetween( dot, 0.0f, 0.88f );
            float fa = std::max(sunAmbient, ambient[0]);

            // Ambient color based on the zenith color in the cube map
            environment->SetAmbientLight( ::Triton::Vector3(fa, fa, fa) );
            //::Triton::Vector3( ambient[0], ambient[1], ambient[2] ) );
        }

        else
        {
            environment->SetDirectionalLight( ::Triton::Vector3(0,0,1), ::Triton::Vector3(1,1,1) );
            environment->SetAmbientLight( ::Triton::Vector3(0.88f, 0.88f, 0.88f) );
        }

        // Build transform from our cube map orientation space to native Triton orientation
        // See worldToCubeMap function used in SkyBox to orient sky texture so that sky is up and earth is down
        osg::Matrix m = osg::Matrix::rotate( osg::PI_2, osg::X_AXIS ); // = worldToCubeMap

        ::Triton::Matrix3 transformFromYUpToZUpCubeMapCoords(
            m(0,0), m(0,1), m(0,2),
            m(1,0), m(1,1), m(1,2),
            m(2,0), m(2,1), m(2,2) );

        // Grab the cube map from our sky box and give it to Triton to use as an _environment map
        // GLenum texture = renderInfo.getState()->getLastAppliedTextureAttribute( _stage, osg::StateAttribute::TEXTURE );
        if ( _cubeMap.valid() )
        {
            environment->SetEnvironmentMap(
                (::Triton::TextureHandle)_cubeMap->getTextureObject( state->getContextID() )->id(), transformFromYUpToZUpCubeMapCoords );

            if( _planarReflectionMap.valid() && _planarReflectionProjection.valid() )
            {
                osg::Matrix & p = *_planarReflectionProjection;

                ::Triton::Matrix3 planarProjection( p(0,0), p(0,1), p(0,2),
                                                    p(1,0), p(1,1), p(1,2),
                                                    p(2,0), p(2,1), p(2,2) );

                environment->SetPlanarReflectionMap( (::Triton::TextureHandle)
                                                     _planarReflectionMap->getTextureObject( state->getContextID() )->id(),
                                                     planarProjection, 0.125  );
            }
        }

        // Draw the ocean for the current time sample
        if ( _TRITON->getOcean() )
        {
            _TRITON->getOcean()->Draw( renderInfo.getView()->getFrameStamp()->getSimulationTime() );
        }
    }

    // Put GL back in a state that won't confuse the OSG state tracking:
    state->dirtyAllVertexArrays();
    state->dirtyAllAttributes();
    //osg::GL2Extensions* api = osg::GL2Extensions::Get(state->getContextID(), true);
    //api->glUseProgram((GLuint)0);
    //state->setLastAppliedProgramObject( 0L );
    state->apply();
}
void
TritonDrawable::drawImplementation(osg::RenderInfo& renderInfo) const
{
    osg::State* state = renderInfo.getState();

    state->disableAllVertexArrays();

    _TRITON->initialize( renderInfo );
    if ( !_TRITON->ready() )
        return;

#ifdef USE_HEIGHT_MAP
    if( !_terrainChangedCallback.valid())
        const_cast< TritonDrawable *>( this )->setupHeightMap(_mapNode.get());
#endif

    ::Triton::Environment* environment = _TRITON->getEnvironment();

    osgEarth::NativeProgramAdapterCollection& adapters = _adapters[ state->getContextID() ];
    if ( adapters.empty() )
    {
        adapters.push_back( new osgEarth::NativeProgramAdapter(state, (GLint)_TRITON->getOcean()->GetShaderObject(::Triton::GOD_RAYS)) );
        adapters.push_back( new osgEarth::NativeProgramAdapter(state, (GLint)_TRITON->getOcean()->GetShaderObject(::Triton::SPRAY_PARTICLES)) );
        adapters.push_back( new osgEarth::NativeProgramAdapter(state, (GLint)_TRITON->getOcean()->GetShaderObject(::Triton::WAKE_SPRAY_PARTICLES)) );
        adapters.push_back( new osgEarth::NativeProgramAdapter(state, (GLint)_TRITON->getOcean()->GetShaderObject(::Triton::WATER_DECALS)) );
        adapters.push_back( new osgEarth::NativeProgramAdapter(state, (GLint)_TRITON->getOcean()->GetShaderObject(::Triton::WATER_SURFACE)) );
        adapters.push_back( new osgEarth::NativeProgramAdapter(state, (GLint)_TRITON->getOcean()->GetShaderObject(::Triton::WATER_SURFACE_PATCH)) );
    }
    adapters.apply( state );

    // Pass the final view and projection matrices into Triton.
    if ( environment )
    {
        environment->SetCameraMatrix( state->getModelViewMatrix().ptr() );
        environment->SetProjectionMatrix( state->getProjectionMatrix().ptr() );
    }

    if(_terrainChangedCallback.valid())
    {
        OceanTerrainChangedCallback* c = static_cast<OceanTerrainChangedCallback*>(_terrainChangedCallback.get());
        c->setViewMatrix( renderInfo.getView()->getCamera()->getViewMatrix() );
        c->setProjectionMatrix(renderInfo.getView()->getCamera()->getProjectionMatrix() );
        c->setContextID(renderInfo.getView()->getCamera()->getGraphicsContext()->getState()->getContextID() );
    }

    state->dirtyAllVertexArrays();

    // Now light and draw the ocean:
    if ( environment )
    {
        // The sun position is roughly where it is in our skybox texture:

        // Since this is a simple example we will just assume that Sun is the light from View light source
        // TODO: fix this...
        osg::Light* light = renderInfo.getView() ? renderInfo.getView()->getLight() : NULL;

        // This is the light attached to View so there are no transformations above..
        // But in general case you would need to accumulate all transforms above the light into this matrix
        osg::Matrix lightLocalToWorldMatrix = osg::Matrix::identity();

        // If you don't know where the sun lightsource is attached and don't know its local to world matrix you may use
        // following elaborate scheme to grab the light source while drawing Triton ocean:
        // - Install cull callback to catch CullVisitor and record pointer to its associated RenderStage
        //   I was hoping RenderStage can be found from renderInfo in drawImplementation but I didn't figure how ...
        // - When TritonDrawable::drawImplementation is called all lights will be already applied to OpenGL
        //   then just find proper infinite directional light by scanning renderStage->PositionalStateContainer.
        // - Note that we canot scan for the lights inside cull because they may not be traversed before Triton drawable
        // - When you found interesting ligt source that can work as Sun, read its modelview matrix and lighting params
        //   Multiply light position by ( modelview * inverse camera view ) and pass this to Triton with lighting colors

        if ( light && light->getPosition().w() == 0 )
        {
            osg::Vec4 ambient = light->getAmbient();
            osg::Vec4 diffuse = light->getDiffuse();
            osg::Vec4 position = light->getPosition();

            // Compute light position/direction in the world
            position = position * lightLocalToWorldMatrix;

            // Diffuse direction and color
            environment->SetDirectionalLight(
                ::Triton::Vector3( position[0], position[1], position[2] ),
                ::Triton::Vector3( diffuse[0],  diffuse[1],  diffuse[2] ) );

            // Ambient color based on the zenith color in the cube map
            environment->SetAmbientLight(
                ::Triton::Vector3( ambient[0], ambient[1], ambient[2] ) );
        }

        // Build transform from our cube map orientation space to native Triton orientation
        // See worldToCubeMap function used in SkyBox to orient sky texture so that sky is up and earth is down
        osg::Matrix m = osg::Matrix::rotate( osg::PI_2, osg::X_AXIS ); // = worldToCubeMap

        ::Triton::Matrix3 transformFromYUpToZUpCubeMapCoords(
            m(0,0), m(0,1), m(0,2),
            m(1,0), m(1,1), m(1,2),
            m(2,0), m(2,1), m(2,2) );

        // Grab the cube map from our sky box and give it to Triton to use as an _environment map
        // GLenum texture = renderInfo.getState()->getLastAppliedTextureAttribute( _stage, osg::StateAttribute::TEXTURE );
        if ( _cubeMap.valid() )
        {
            environment->SetEnvironmentMap(
                (::Triton::TextureHandle)_cubeMap->getTextureObject( state->getContextID() )->id(), transformFromYUpToZUpCubeMapCoords );

            if( _planarReflectionMap.valid() && _planarReflectionProjection.valid() )
            {
                osg::Matrix & p = *_planarReflectionProjection;

                ::Triton::Matrix3 planarProjection( p(0,0), p(0,1), p(0,2),
                                                    p(1,0), p(1,1), p(1,2),
                                                    p(2,0), p(2,1), p(2,2) );

                environment->SetPlanarReflectionMap( (::Triton::TextureHandle)
                                                      _planarReflectionMap->getTextureObject( state->getContextID() )->id(),
                                                      planarProjection, 0.125  );
            }
        }

        // Draw the ocean for the current time sample
        if ( _TRITON->getOcean() )
        {
            _TRITON->getOcean()->Draw( renderInfo.getView()->getFrameStamp()->getSimulationTime() );
        }
    }

    state->dirtyAllVertexArrays();
}