// Attempts to position unplaced rectangles from the layout into this row. int TextureLayoutRow::Generate(TextureLayout& layout, int max_width, int y) { int placed_rectangles = 0; while(!layout.unplaced_rectangles.empty()) { TextureLayoutRectangle* rectangle = layout.unplaced_rectangles.front(); if (placed_width + rectangle->GetDimensions().x + 1 > max_width) break; // Increment the row height if necessary. height = Math::Max(height, rectangle->GetDimensions().y); // Add this glyph onto our list and mark it as placed. rectangles.push_back(rectangle); if (layout.has_generated) rectangle->Place(layout.GetNumTextures()-1, Vector2i(placed_width, y)); else rectangle->Place(layout.GetNumTextures(), Vector2i(placed_width, y)); ++placed_rectangles; // Increment our width. An extra pixel is added on so the rectangles aren't pushed up // against each other. This will avoid filtering artifacts. if (rectangle->GetDimensions().x > 0) placed_width += rectangle->GetDimensions().x + 1; layout.rectangles.push_back(rectangle); layout.unplaced_rectangles.pop(); } return placed_rectangles; }
void TextureCompositorMultiTexture::applyLayerUpdate(osg::StateSet* stateSet, UID layerUID, const GeoImage& preparedImage, const TileKey& tileKey, const TextureLayout& layout, osg::StateSet* parentStateSet) const { osg::Texture2D* tex = s_getTexture( stateSet, layerUID, layout, parentStateSet, _minFilter, _magFilter); if ( tex ) { osg::Image* image = preparedImage.getImage(); image->dirty(); // required for ensure the texture recognizes the image as new data tex->setImage( image ); // set up proper mipmapping filters: if (_enableMipmapping && _enableMipmappingOnUpdatedTextures && ImageUtils::isPowerOfTwo( image ) && !(!image->isMipmap() && ImageUtils::isCompressed(image)) ) { if ( tex->getFilter(osg::Texture::MIN_FILTER) != _minFilter ) tex->setFilter( osg::Texture::MIN_FILTER, _minFilter ); } else if ( tex->getFilter(osg::Texture::MIN_FILTER) != osg::Texture::LINEAR ) { tex->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR ); } bool lodBlending = layout.getSlot(layerUID, 1) >= 0; if (_enableMipmapping && _enableMipmappingOnUpdatedTextures && lodBlending ) { int slot = layout.getSlot(layerUID, 0); // update the timestamp on the image layer to support blending. float now = (float)osg::Timer::instance()->delta_s( osg::Timer::instance()->getStartTick(), osg::Timer::instance()->tick() ); ArrayUniform stampUniform( "osgearth_SlotStamp", osg::Uniform::FLOAT, stateSet, layout.getMaxUsedSlot() + 1 ); stampUniform.setElement( slot, now ); // set the texture matrix to properly position the blend (parent) texture osg::Matrix mat; if ( parentStateSet != 0L ) { unsigned tileX, tileY; tileKey.getTileXY(tileX, tileY); mat(0,0) = 0.5f; mat(1,1) = 0.5f; mat(3,0) = (float)(tileX % 2) * 0.5f; mat(3,1) = (float)(1 - tileY % 2) * 0.5f; } ArrayUniform texMatUniform( "osgearth_TexBlendMatrix", osg::Uniform::FLOAT_MAT4, stateSet, layout.getMaxUsedSlot() + 1 ); texMatUniform.setElement( slot, mat ); } } }
void RenderColourLayerToTexture::doRender( Position const & p_position , Size const & p_size , TextureLayout const & p_texture , RenderPipeline & p_pipeline , MatrixUbo & p_matrixUbo , GeometryBuffers const & p_geometryBuffers , uint32_t p_layer ) { REQUIRE( p_texture.getLayersCount() > p_layer ); m_viewport.setPosition( p_position ); m_viewport.resize( p_size ); m_viewport.update(); m_viewport.apply(); REQUIRE( m_layerIndexUniform ); m_layerIndexUniform->setValue( p_layer ); p_matrixUbo.update( m_viewport.getProjection() ); p_pipeline.apply(); m_layerIndexUniform->update(); p_texture.bind( MinTextureIndex ); m_sampler->bind( MinTextureIndex ); p_geometryBuffers.draw( uint32_t( m_arrayVertex.size() ), 0u ); m_sampler->unbind( MinTextureIndex ); p_texture.unbind( MinTextureIndex ); }
// Attempts to position unplaced rectangles from the layout into this row. int TextureLayoutRow::Generate(TextureLayout& layout, int max_width, int y) { int width = 1; int first_unplaced_index = 0; int placed_rectangles = 0; while (width < max_width) { // Find the first unplaced rectangle we can fit. int index; for (index = first_unplaced_index; index < layout.GetNumRectangles(); ++index) { TextureLayoutRectangle& rectangle = layout.GetRectangle(index); if (!rectangle.IsPlaced()) { if (width + rectangle.GetDimensions().x + 1 <= max_width) break; } } if (index == layout.GetNumRectangles()) return placed_rectangles; TextureLayoutRectangle& rectangle = layout.GetRectangle(index); // Increment the row height if necessary. height = Math::Max(height, rectangle.GetDimensions().y); // Add this glyph onto our list and mark it as placed. rectangles.push_back(&rectangle); rectangle.Place(layout.GetNumTextures(), Vector2i(width, y)); ++placed_rectangles; // Increment our width. An extra pixel is added on so the rectangles aren't pushed up // against each other. This will avoid filtering artifacts. if (rectangle.GetDimensions().x > 0) width += rectangle.GetDimensions().x + 1; first_unplaced_index = index + 1; } return placed_rectangles; }
void TextureCompositorMultiTexture::updateMasterStateSet(osg::StateSet* stateSet, const TextureLayout& layout ) const { int numSlots = layout.getMaxUsedSlot() + 1; int maxUnits = numSlots; if ( _useGPU ) { // Validate against the max number of GPU texture units: if ( maxUnits > Registry::instance()->getCapabilities().getMaxGPUTextureUnits() ) { maxUnits = Registry::instance()->getCapabilities().getMaxGPUTextureUnits(); OE_WARN << LC << "Warning! You have exceeded the number of texture units available on your GPU (" << maxUnits << "). Consider using another compositing mode." << std::endl; } VirtualProgram* vp = static_cast<VirtualProgram*>( stateSet->getAttribute(VirtualProgram::SA_TYPE) ); // see if we have any blended layers: bool hasBlending = layout.containsSecondarySlots( maxUnits ); // Why are these marked as PROTECTED? See the comments in MapNode.cpp for the answer. // (Where it sets up the top-level VirtualProgram) vp->setFunction( "oe_multicomp_vertex", s_createTextureVertexShader(layout, hasBlending), ShaderComp::LOCATION_VERTEX_MODEL, 0.0 ); vp->setFunction( "oe_multicomp_fragment", s_createTextureFragShaderFunction(layout, maxUnits, hasBlending, _lodTransitionTime), ShaderComp::LOCATION_FRAGMENT_COLORING, 0.0 ); //vp->setShader( // "osgearth_vert_setupColoring", // s_createTextureVertexShader(layout, hasBlending), // osg::StateAttribute::ON | osg::StateAttribute::PROTECTED ); //vp->setShader( // "osgearth_frag_applyColoring", // s_createTextureFragShaderFunction(layout, maxUnits, hasBlending, _lodTransitionTime), // osg::StateAttribute::ON | osg::StateAttribute::PROTECTED ); } else { // Forcably disable shaders stateSet->setAttributeAndModes( new osg::Program(), osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED ); // Validate against the maximum number of textures available in FFP mode. if ( maxUnits > Registry::instance()->getCapabilities().getMaxFFPTextureUnits() ) { maxUnits = Registry::instance()->getCapabilities().getMaxFFPTextureUnits(); OE_WARN << LC << "Warning! You have exceeded the number of texture units available in fixed-function pipeline " "mode on your graphics hardware (" << maxUnits << "). Consider using another " "compositing mode." << std::endl; } // FFP multitexturing requires that we set up a series of TexCombine attributes: if (maxUnits == 1) { osg::TexEnv* texenv = new osg::TexEnv(osg::TexEnv::MODULATE); stateSet->setTextureAttributeAndModes(0, texenv, osg::StateAttribute::ON); } else if (maxUnits >= 2) { //Blend together the colors and accumulate the alpha values of textures 0 and 1 on unit 0 { osg::TexEnvCombine* texenv = new osg::TexEnvCombine; texenv->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); texenv->setCombine_Alpha(osg::TexEnvCombine::ADD); texenv->setSource0_RGB(osg::TexEnvCombine::TEXTURE0+1); texenv->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR); texenv->setSource0_Alpha(osg::TexEnvCombine::TEXTURE0+1); texenv->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA); texenv->setSource1_RGB(osg::TexEnvCombine::TEXTURE0+0); texenv->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR); texenv->setSource1_Alpha(osg::TexEnvCombine::TEXTURE0+0); texenv->setOperand1_Alpha(osg::TexEnvCombine::SRC_ALPHA); texenv->setSource2_RGB(osg::TexEnvCombine::TEXTURE0+1); texenv->setOperand2_RGB(osg::TexEnvCombine::SRC_ALPHA); stateSet->setTextureAttributeAndModes(0, texenv, osg::StateAttribute::ON); } //For textures 2 and beyond, blend them together with the previous //Add the alpha values of this unit and the previous unit for (int unit = 1; unit < maxUnits-1; ++unit) { osg::TexEnvCombine* texenv = new osg::TexEnvCombine; texenv->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); texenv->setCombine_Alpha(osg::TexEnvCombine::ADD); texenv->setSource0_RGB(osg::TexEnvCombine::TEXTURE0+unit+1); texenv->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR); texenv->setSource0_Alpha(osg::TexEnvCombine::TEXTURE0+unit+1); texenv->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA); texenv->setSource1_RGB(osg::TexEnvCombine::PREVIOUS); texenv->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR); texenv->setSource1_Alpha(osg::TexEnvCombine::PREVIOUS); texenv->setOperand1_Alpha(osg::TexEnvCombine::SRC_ALPHA); texenv->setSource2_RGB(osg::TexEnvCombine::TEXTURE0+unit+1); texenv->setOperand2_RGB(osg::TexEnvCombine::SRC_ALPHA); stateSet->setTextureAttributeAndModes(unit, texenv, osg::StateAttribute::ON); } //Modulate the colors to get proper lighting on the last unit //Keep the alpha results from the previous stage { osg::TexEnvCombine* texenv = new osg::TexEnvCombine; texenv->setCombine_RGB(osg::TexEnvCombine::MODULATE); texenv->setCombine_Alpha(osg::TexEnvCombine::REPLACE); texenv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); texenv->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR); texenv->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS); texenv->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA); texenv->setSource1_RGB(osg::TexEnvCombine::PRIMARY_COLOR); texenv->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR); stateSet->setTextureAttributeAndModes(maxUnits-1, texenv, osg::StateAttribute::ON); } } } }
void TextureCompositorTexArray::applyLayerUpdate(osg::StateSet* stateSet, UID layerUID, const GeoImage& preparedImage, const TileKey& tileKey, const TextureLayout& layout, osg::StateSet* parentStateSet) const { GeoExtent tileExtent(tileKey.getExtent()); int slot = layout.getSlot( layerUID ); if ( slot < 0 ) return; // means the layer no longer exists // access the texture array, creating or growing it if necessary: osg::Texture2DArray* texture = s_getTexture( stateSet, layout, 0, textureSize() ); ensureSampler( stateSet, 0 ); // assign the new image at the proper position in the texture array. osg::Image* image = preparedImage.getImage(); assignImage(texture, slot, image); // update the region uniform to reflect the geo extent of the image: const GeoExtent& imageExtent = preparedImage.getExtent(); osg::Vec4 tileTransform; getImageTransform(tileExtent, imageExtent, tileTransform); // access the region uniform, creating or growing it if necessary: ArrayUniform regionUni( "region", osg::Uniform::FLOAT, stateSet, layout.getMaxUsedSlot()+1 ); if ( regionUni.isValid() ) { int layerOffset = slot * 8; for (int i = 0; i < 4; ++i) regionUni.setElement( layerOffset + i, tileTransform[i]); //region->dirty(); } if ( layout.isBlendingEnabled( layerUID ) && regionUni.isValid() ) { osg::Uniform* secondarySampler = ensureSampler( stateSet, 1 ); osg::Texture2DArray* parentTexture = 0; const unsigned parentLayerOffset = slot * 8 + 4; if ( parentStateSet ) { ArrayUniform parentRegion( "region", osg::Uniform::FLOAT, parentStateSet, layout.getMaxUsedSlot()+1 ); //osg::Uniform* parentRegion = s_getRegionUniform( parentStateSet, // layout ); GeoExtent parentExtent(tileKey.createParentKey().getExtent()); float widthRatio, heightRatio; parentRegion.getElement(slot * 8 + 2, widthRatio); parentRegion.getElement(slot * 8 + 3, heightRatio); float parentImageWidth = parentExtent.width() / widthRatio; float parentImageHeight = parentExtent.height() / heightRatio; float xRatio, yRatio; parentRegion.getElement(slot * 8, xRatio); parentRegion.getElement(slot * 8 + 1, yRatio); float ParentImageXmin = parentExtent.xMin() - xRatio * parentImageWidth; float ParentImageYmin = parentExtent.yMin() - yRatio * parentImageHeight; regionUni.setElement(parentLayerOffset, static_cast<float>((tileExtent.xMin() - ParentImageXmin) / parentImageWidth)); regionUni.setElement(parentLayerOffset + 1, static_cast<float>((tileExtent.yMin() - ParentImageYmin) / parentImageHeight)); regionUni.setElement(parentLayerOffset + 2, static_cast<float>(tileExtent.width() / parentImageWidth)); regionUni.setElement(parentLayerOffset + 3, static_cast<float>(tileExtent.height() / parentImageHeight)); //regionUni.dirty(); parentTexture = static_cast<osg::Texture2DArray*>(parentStateSet->getTextureAttribute(0, osg::StateAttribute::TEXTURE)); } else { // setting the parent transform values to -1 disabled blending for this layer. #hack -gw for (int i = 0; i < 4; ++i) regionUni.setElement(parentLayerOffset + i, tileTransform[i]); } if (parentTexture) stateSet->setTextureAttribute(1, parentTexture, osg::StateAttribute::ON); else secondarySampler->set(0); // update the timestamp on the image layer to support fade-in blending. float now = (float)osg::Timer::instance()->delta_s( osg::Timer::instance()->getStartTick(), osg::Timer::instance()->tick() ); ArrayUniform stampUniform( "osgearth_SlotStamp", osg::Uniform::FLOAT, stateSet, layout.getMaxUsedSlot()+1 ); stampUniform.setElement( slot, now ); } }