void MPGeometry::renderPrimitiveSets(osg::State& state, bool usingVBOs) const { // check the map frame to see if it's up to date if ( _frame.needsSync() ) { // this lock protects a MapFrame sync when we have multiple DRAW threads. Threading::ScopedMutexLock exclusive( _frameSyncMutex ); if ( _frame.needsSync() && _frame.sync() ) // always double check { // This should only happen is the layer ordering changes; // If layers are added or removed, the Tile gets rebuilt and // the point is moot. std::vector<Layer> reordered; const ImageLayerVector& layers = _frame.imageLayers(); reordered.reserve( layers.size() ); for( ImageLayerVector::const_iterator i = layers.begin(); i != layers.end(); ++i ) { std::vector<Layer>::iterator j = std::find( _layers.begin(), _layers.end(), i->get()->getUID() ); if ( j != _layers.end() ) reordered.push_back( *j ); } _layers.swap( reordered ); } } unsigned layersDrawn = 0; osg::ref_ptr<osg::GL2Extensions> ext = osg::GL2Extensions::Get( state.getContextID(), true ); const osg::Program::PerContextProgram* pcp = state.getLastAppliedProgramObject(); GLint opacityLocation; GLint uidLocation; GLint orderLocation; GLint texMatParentLocation; // yes, it's possible that the PCP is not set up yet. // TODO: can we optimize this so we don't need to get uni locations every time? if ( pcp ) { opacityLocation = pcp->getUniformLocation( _opacityUniform->getNameID() ); uidLocation = pcp->getUniformLocation( _layerUIDUniform->getNameID() ); orderLocation = pcp->getUniformLocation( _layerOrderUniform->getNameID() ); texMatParentLocation = pcp->getUniformLocation( _texMatParentUniform->getNameID() ); } // activate the tile coordinate set - same for all layers state.setTexCoordPointer( _imageUnit+1, _tileCoords.get() ); if ( _layers.size() > 0 ) { float prev_opacity = -1.0f; float prev_alphaThreshold = -1.0f; // first bind any shared layers // TODO: optimize by pre-storing shared indexes for(unsigned i=0; i<_layers.size(); ++i) { const Layer& layer = _layers[i]; // a "shared" layer binds to a secondary texture unit so that other layers // can see it and use it. if ( layer._imageLayer->isShared() ) { int sharedUnit = layer._imageLayer->shareImageUnit().get(); { state.setActiveTextureUnit( sharedUnit ); state.setTexCoordPointer( sharedUnit, layer._texCoords.get() ); // bind the texture for this layer to the active share unit. layer._tex->apply( state ); // no texture LOD blending for shared layers for now. maybe later. } } } // track the active image unit. int activeImageUnit = -1; // interate over all the image layers for(unsigned i=0; i<_layers.size(); ++i) { const Layer& layer = _layers[i]; if ( layer._imageLayer->getVisible() ) { // activate the visible unit if necessary: if ( activeImageUnit != _imageUnit ) { state.setActiveTextureUnit( _imageUnit ); activeImageUnit = _imageUnit; } // bind the texture for this layer: layer._tex->apply( state ); // if we're using a parent texture for blending, activate that now if ( layer._texParent.valid() ) { state.setActiveTextureUnit( _imageUnitParent ); activeImageUnit = _imageUnitParent; layer._texParent->apply( state ); } // bind the texture coordinates for this layer. // TODO: can probably optimize this by sharing or using texture matrixes. // State::setTexCoordPointer does some redundant work under the hood. state.setTexCoordPointer( _imageUnit, layer._texCoords.get() ); // apply uniform values: if ( pcp ) { // apply opacity: float opacity = layer._imageLayer->getOpacity(); if ( opacity != prev_opacity ) { _opacityUniform->set( opacity ); _opacityUniform->apply( ext, opacityLocation ); prev_opacity = opacity; } // assign the layer UID: _layerUIDUniform->set( layer._layerID ); _layerUIDUniform->apply( ext, uidLocation ); // assign the layer order: _layerOrderUniform->set( (int)layersDrawn ); _layerOrderUniform->apply( ext, orderLocation ); // assign the parent texture matrix if ( layer._texParent.valid() ) { _texMatParentUniform->set( layer._texMatParent ); _texMatParentUniform->apply( ext, texMatParentLocation ); } } // draw the primitive sets. for(unsigned int primitiveSetNum=0; primitiveSetNum!=_primitives.size(); ++primitiveSetNum) { const osg::PrimitiveSet* primitiveset = _primitives[primitiveSetNum].get(); primitiveset->draw(state, usingVBOs); } ++layersDrawn; } } // prevent texture leakage glBindTexture( GL_TEXTURE_2D, 0 ); } // if we didn't draw anything, draw the raw tiles anyway with no texture. if ( layersDrawn == 0 ) { _opacityUniform->set( 1.0f ); _opacityUniform->apply( ext, opacityLocation ); _layerUIDUniform->set( (int)-1 ); // indicates a non-textured layer _layerUIDUniform->apply( ext, uidLocation ); _layerOrderUniform->set( (int)0 ); _layerOrderUniform->apply( ext, orderLocation ); // draw the primitives themselves. for(unsigned int primitiveSetNum=0; primitiveSetNum!=_primitives.size(); ++primitiveSetNum) { const osg::PrimitiveSet* primitiveset = _primitives[primitiveSetNum].get(); primitiveset->draw(state, usingVBOs); } } }
void MPGeometry::renderPrimitiveSets(osg::State& state, bool renderColor, bool usingVBOs) const { // check the map frame to see if it's up to date if ( _frame.needsSync() ) { // this lock protects a MapFrame sync when we have multiple DRAW threads. Threading::ScopedMutexLock exclusive( _frameSyncMutex ); if ( _frame.needsSync() && _frame.sync() ) // always double check { // This should only happen is the layer ordering changes; // If layers are added or removed, the Tile gets rebuilt and // the point is moot. std::vector<Layer> reordered; const ImageLayerVector& layers = _frame.imageLayers(); reordered.reserve( layers.size() ); for( ImageLayerVector::const_iterator i = layers.begin(); i != layers.end(); ++i ) { std::vector<Layer>::iterator j = std::find( _layers.begin(), _layers.end(), i->get()->getUID() ); if ( j != _layers.end() ) reordered.push_back( *j ); } _layers.swap( reordered ); } } unsigned layersDrawn = 0; // access the GL extensions interface for the current GC: const osg::Program::PerContextProgram* pcp = 0L; #if OSG_MIN_VERSION_REQUIRED(3,3,3) osg::ref_ptr<osg::GLExtensions> ext; #else osg::ref_ptr<osg::GL2Extensions> ext; #endif unsigned contextID; if (_supportsGLSL) { contextID = state.getContextID(); #if OSG_MIN_VERSION_REQUIRED(3,3,3) ext = osg::GLExtensions::Get(contextID, true); #else ext = osg::GL2Extensions::Get( contextID, true ); #endif pcp = state.getLastAppliedProgramObject(); } // cannot store these in the object since there could be multiple GCs (and multiple // PerContextPrograms) at large GLint tileKeyLocation = -1; GLint birthTimeLocation = -1; GLint opacityLocation = -1; GLint uidLocation = -1; GLint orderLocation = -1; GLint texMatParentLocation = -1; GLint minRangeLocation = -1; GLint maxRangeLocation = -1; // The PCP can change (especially in a VirtualProgram environment). So we do need to // requery the uni locations each time unfortunately. TODO: explore optimizations. if ( pcp ) { tileKeyLocation = pcp->getUniformLocation( _tileKeyUniformNameID ); birthTimeLocation = pcp->getUniformLocation( _birthTimeUniformNameID ); opacityLocation = pcp->getUniformLocation( _opacityUniformNameID ); uidLocation = pcp->getUniformLocation( _uidUniformNameID ); orderLocation = pcp->getUniformLocation( _orderUniformNameID ); texMatParentLocation = pcp->getUniformLocation( _texMatParentUniformNameID ); minRangeLocation = pcp->getUniformLocation( _minRangeUniformNameID ); maxRangeLocation = pcp->getUniformLocation( _maxRangeUniformNameID ); } // apply the tilekey uniform once. if ( tileKeyLocation >= 0 ) { ext->glUniform4fv( tileKeyLocation, 1, _tileKeyValue.ptr() ); } // set the "birth time" - i.e. the time this tile last entered the scene in the current GC. if ( birthTimeLocation >= 0 ) { PerContextData& pcd = _pcd[contextID]; if ( pcd.birthTime < 0.0f ) { const osg::FrameStamp* stamp = state.getFrameStamp(); if ( stamp ) { pcd.birthTime = stamp->getReferenceTime(); } } ext->glUniform1f( birthTimeLocation, pcd.birthTime ); } // activate the tile coordinate set - same for all layers if ( renderColor ) { state.setTexCoordPointer( _imageUnit+1, _tileCoords.get() ); } #ifndef OSG_GLES2_AVAILABLE if ( renderColor ) { // emit a default terrain color since we're not binding a color array: glColor4f(1.0f, 1.0f, 1.0f, 1.0f); } #endif // activate the elevation texture if there is one. Same for all layers. //if ( _elevTex.valid() ) //{ // state.setActiveTextureUnit( 2 ); // state.setTexCoordPointer( 1, _tileCoords.get() ); // necessary?? since we do it above // _elevTex->apply( state ); // // todo: probably need an elev texture matrix as well. -gw //} // track the active image unit. int activeImageUnit = -1; // remember whether we applied a parent texture. bool usedTexParent = false; if ( _layers.size() > 0 ) { float prev_opacity = -1.0f; // first bind any shared layers. We still have to do this even if we are // in !renderColor mode b/c these textures could be used by vertex shaders // to alter the geometry. int sharedLayers = 0; if ( pcp ) { for(unsigned i=0; i<_layers.size(); ++i) { const Layer& layer = _layers[i]; // a "shared" layer binds to a secondary texture unit so that other layers // can see it and use it. if ( layer._imageLayer->isShared() ) { ++sharedLayers; int sharedUnit = layer._imageLayer->shareImageUnit().get(); { state.setActiveTextureUnit( sharedUnit ); state.setTexCoordPointer( sharedUnit, layer._texCoords.get() ); // bind the texture for this layer to the active share unit. layer._tex->apply( state ); // Shared layers need a texture matrix since the terrain engine doesn't // provide a "current texture coordinate set" uniform (i.e. oe_layer_texc) GLint texMatLocation = 0; texMatLocation = pcp->getUniformLocation( layer._texMatUniformID ); if ( texMatLocation >= 0 ) { ext->glUniformMatrix4fv( texMatLocation, 1, GL_FALSE, layer._texMat.ptr() ); } } } } } if (renderColor) { // find the first opaque layer, top-down, and start there: unsigned first = 0; for(first = _layers.size()-1; first > 0; --first) { const Layer& layer = _layers[first]; if (layer._opaque && //Color filters can modify the opacity layer._imageLayer->getColorFilters().empty() && layer._imageLayer->getVisible() && layer._imageLayer->getOpacity() >= 1.0f) { break; } } // interate over all the image layers for(unsigned i=first; i<_layers.size(); ++i) { const Layer& layer = _layers[i]; if ( layer._imageLayer->getVisible() && layer._imageLayer->getOpacity() > 0.0f ) { // activate the visible unit if necessary: if ( activeImageUnit != _imageUnit ) { state.setActiveTextureUnit( _imageUnit ); activeImageUnit = _imageUnit; } // bind the texture for this layer: layer._tex->apply( state ); // in FFP mode, we need to enable the GL mode for texturing: if ( !pcp ) //!_supportsGLSL) { state.applyMode(GL_TEXTURE_2D, true); } // if we're using a parent texture for blending, activate that now if ( texMatParentLocation >= 0 && layer._texParent.valid() ) { state.setActiveTextureUnit( _imageUnitParent ); activeImageUnit = _imageUnitParent; layer._texParent->apply( state ); usedTexParent = true; } // bind the texture coordinates for this layer. // TODO: can probably optimize this by sharing or using texture matrixes. // State::setTexCoordPointer does some redundant work under the hood. state.setTexCoordPointer( _imageUnit, layer._texCoords.get() ); // apply uniform values: if ( pcp ) { // apply opacity: if ( opacityLocation >= 0 ) { float opacity = layer._imageLayer->getOpacity(); if ( opacity != prev_opacity ) { ext->glUniform1f( opacityLocation, (GLfloat)opacity ); prev_opacity = opacity; } } // assign the layer UID: if ( uidLocation >= 0 ) { ext->glUniform1i( uidLocation, (GLint)layer._layerID ); } // assign the layer order: if ( orderLocation >= 0 ) { ext->glUniform1i( orderLocation, (GLint)layersDrawn ); } // assign the parent texture matrix if ( texMatParentLocation >= 0 && layer._texParent.valid() ) { ext->glUniformMatrix4fv( texMatParentLocation, 1, GL_FALSE, layer._texMatParent.ptr() ); } // assign the min range if ( minRangeLocation >= 0 ) { ext->glUniform1f( minRangeLocation, layer._imageLayer->getImageLayerOptions().minVisibleRange().get() ); } // assign the max range if ( maxRangeLocation >= 0 ) { ext->glUniform1f( maxRangeLocation, layer._imageLayer->getImageLayerOptions().maxVisibleRange().get() ); } } // draw the primitive sets. for(unsigned int primitiveSetNum=0; primitiveSetNum!=_primitives.size(); ++primitiveSetNum) { const osg::PrimitiveSet* primitiveset = _primitives[primitiveSetNum].get(); if ( primitiveset ) { primitiveset->draw(state, usingVBOs); } else { OE_WARN << LC << "Strange, MPGeometry had a 0L primset" << std::endl; } } ++layersDrawn; } } } } // if we didn't draw anything, draw the raw tiles anyway with no texture. if ( layersDrawn == 0 ) { if ( pcp ) { if ( opacityLocation >= 0 ) ext->glUniform1f( opacityLocation, (GLfloat)1.0f ); if ( uidLocation >= 0 ) ext->glUniform1i( uidLocation, (GLint)-1 ); if ( orderLocation >= 0 ) ext->glUniform1i( orderLocation, (GLint)0 ); } // draw the primitives themselves. for(unsigned int primitiveSetNum=0; primitiveSetNum!=_primitives.size(); ++primitiveSetNum) { const osg::PrimitiveSet* primitiveset = _primitives[primitiveSetNum].get(); primitiveset->draw(state, usingVBOs); } } else // at least one textured layer was drawn: { // prevent texture leakage // TODO: find a way to remove this to speed things up if ( renderColor ) { glBindTexture( GL_TEXTURE_2D, 0 ); // if a parent texture was applied, need to disable both. if ( usedTexParent ) { state.setActiveTextureUnit( activeImageUnit != _imageUnitParent ? _imageUnitParent : _imageUnit ); glBindTexture( GL_TEXTURE_2D, 0); } } } }
void MPGeometry::renderPrimitiveSets(osg::State& state, bool usingVBOs) const { // check the map frame to see if it's up to date if ( _frame.needsSync() ) { // this lock protects a MapFrame sync when we have multiple DRAW threads. Threading::ScopedMutexLock exclusive( _frameSyncMutex ); if ( _frame.needsSync() && _frame.sync() ) // always double check { // This should only happen is the layer ordering changes; // If layers are added or removed, the Tile gets rebuilt and // the point is moot. std::vector<Layer> reordered; const ImageLayerVector& layers = _frame.imageLayers(); reordered.reserve( layers.size() ); for( ImageLayerVector::const_iterator i = layers.begin(); i != layers.end(); ++i ) { std::vector<Layer>::iterator j = std::find( _layers.begin(), _layers.end(), i->get()->getUID() ); if ( j != _layers.end() ) reordered.push_back( *j ); } _layers.swap( reordered ); } } unsigned layersDrawn = 0; // access the GL extensions interface for the current GC: osg::ref_ptr<osg::GL2Extensions> ext = osg::GL2Extensions::Get( state.getContextID(), true ); const osg::Program::PerContextProgram* pcp = state.getLastAppliedProgramObject(); // cannot store these in the object since there could be multiple GCs (and multiple // PerContextPrograms) at large GLint tileKeyLocation; GLint opacityLocation; GLint uidLocation; GLint orderLocation; GLint texMatParentLocation; // The PCP can change (especially in a VirtualProgram environment). So we do need to // requery the uni locations each time unfortunately. TODO: explore optimizations. if ( pcp ) { tileKeyLocation = pcp->getUniformLocation( _tileKeyUniformNameID ); opacityLocation = pcp->getUniformLocation( _opacityUniformNameID ); uidLocation = pcp->getUniformLocation( _uidUniformNameID ); orderLocation = pcp->getUniformLocation( _orderUniformNameID ); texMatParentLocation = pcp->getUniformLocation( _texMatParentUniformNameID ); } // apply the tilekey uniform once. ext->glUniform4fv( tileKeyLocation, 1, _tileKeyValue.ptr() ); // activate the tile coordinate set - same for all layers state.setTexCoordPointer( _imageUnit+1, _tileCoords.get() ); if ( _layers.size() > 0 ) { float prev_opacity = -1.0f; float prev_alphaThreshold = -1.0f; // first bind any shared layers // TODO: optimize by pre-storing shared indexes for(unsigned i=0; i<_layers.size(); ++i) { const Layer& layer = _layers[i]; // a "shared" layer binds to a secondary texture unit so that other layers // can see it and use it. if ( layer._imageLayer->isShared() ) { int sharedUnit = layer._imageLayer->shareImageUnit().get(); { state.setActiveTextureUnit( sharedUnit ); state.setTexCoordPointer( sharedUnit, layer._texCoords.get() ); // bind the texture for this layer to the active share unit. layer._tex->apply( state ); // no texture LOD blending for shared layers for now. maybe later. } } } // track the active image unit. int activeImageUnit = -1; // interate over all the image layers //glDepthMask(GL_TRUE); for(unsigned i=0; i<_layers.size(); ++i) { // if ( i > 0 ) // glDepthMask(GL_FALSE); const Layer& layer = _layers[i]; if ( layer._imageLayer->getVisible() ) { // activate the visible unit if necessary: if ( activeImageUnit != _imageUnit ) { state.setActiveTextureUnit( _imageUnit ); activeImageUnit = _imageUnit; } // bind the texture for this layer: layer._tex->apply( state ); // if we're using a parent texture for blending, activate that now if ( layer._texParent.valid() ) { state.setActiveTextureUnit( _imageUnitParent ); activeImageUnit = _imageUnitParent; layer._texParent->apply( state ); } // bind the texture coordinates for this layer. // TODO: can probably optimize this by sharing or using texture matrixes. // State::setTexCoordPointer does some redundant work under the hood. state.setTexCoordPointer( _imageUnit, layer._texCoords.get() ); // apply uniform values: if ( pcp ) { // apply opacity: float opacity = layer._imageLayer->getOpacity(); if ( opacity != prev_opacity ) { ext->glUniform1f( opacityLocation, (GLfloat)opacity ); prev_opacity = opacity; } // assign the layer UID: ext->glUniform1i( uidLocation, (GLint)layer._layerID ); // assign the layer order: ext->glUniform1i( orderLocation, (GLint)layersDrawn ); // assign the parent texture matrix if ( layer._texParent.valid() ) { ext->glUniformMatrix4fv( texMatParentLocation, 1, GL_FALSE, layer._texMatParent.ptr() ); } } // draw the primitive sets. for(unsigned int primitiveSetNum=0; primitiveSetNum!=_primitives.size(); ++primitiveSetNum) { const osg::PrimitiveSet* primitiveset = _primitives[primitiveSetNum].get(); primitiveset->draw(state, usingVBOs); } ++layersDrawn; } } // prevent texture leakage // TODO: find a way to remove this to speed things up glBindTexture( GL_TEXTURE_2D, 0 ); } // if we didn't draw anything, draw the raw tiles anyway with no texture. if ( layersDrawn == 0 ) { ext->glUniform1f( opacityLocation, (GLfloat)1.0f ); ext->glUniform1i( uidLocation, (GLint)-1 ); ext->glUniform1i( orderLocation, (GLint)0 ); // draw the primitives themselves. for(unsigned int primitiveSetNum=0; primitiveSetNum!=_primitives.size(); ++primitiveSetNum) { const osg::PrimitiveSet* primitiveset = _primitives[primitiveSetNum].get(); primitiveset->draw(state, usingVBOs); } } }